source

뷰 모델에서 WPF의 TextBox에 포커스 설정

ittop 2023. 4. 22. 10:30
반응형

뷰 모델에서 WPF의 TextBox에 포커스 설정

는 나나 a a a가 있다TextBox a. a. a.Button내가 보기엔

했을 때 를 에 해야 .TextBox★★★★★★ 。

if (companyref == null)
{
    var cs = new Lipper.Nelson.AdminClient.Main.Views.ContactPanels.CompanyAssociation(); 

    MessageBox.Show("Company does not exist.", "Error", MessageBoxButton.OK,
                    MessageBoxImage.Exclamation);

    cs.txtCompanyID.Focusable = true;

    System.Windows.Input.Keyboard.Focus(cs.txtCompanyID);
}

위의 코드는 ViewModel에 있습니다.

CompanyAssociation아아아아아아아아아아아아아아아아아아아아아아.

가 안 요.TextBox.

xaml은 다음과 같습니다.

<igEditors:XamTextEditor Name="txtCompanyID" 
                         KeyDown="xamTextEditorAllowOnlyNumeric_KeyDown"
                         ValueChanged="txtCompanyID_ValueChanged"
                         Text="{Binding Company.CompanyId,
                                        Mode=TwoWay,
                                        UpdateSourceTrigger=PropertyChanged}"
                         Width="{Binding ActualWidth, ElementName=border}"
                         Grid.Column="1" Grid.Row="0"
                         VerticalAlignment="Top"
                         HorizontalAlignment="Stretch"
                         Margin="0,5,0,0"
                         IsEnabled="{Binding Path=IsEditable}"/>

<Button Template="{StaticResource buttonTemp1}"
        Command="{Binding ContactCommand}"
        CommandParameter="searchCompany"
        Content="Search"
        Width="80"
        Grid.Row="0" Grid.Column="2"
        VerticalAlignment="Top"
        Margin="0"
        HorizontalAlignment="Left"
        IsEnabled="{Binding Path=IsEditable}"/>

당신의 질문에 세 부분으로 나누어 대답하겠습니다.

  1. cs.txtCompany가 뭔지 궁금해요.아이디'를 예로 들 수 있나요?TextBox 컨트롤입니까?만약 그렇다면, 당신은 잘못된 길을 가고 있는 것입니다.일반적으로 ViewModel에서 UI를 참조하는 것은 좋지 않습니다.「Why?」라고 질문할 수 있습니다만, 이것은 Stackoverflow :)에 투고하는 다른 질문입니다.

  2. Focus에서 문제를 추적하는 가장 좋은 방법은...디버깅을 합니다.넷 소스 코드설마 농담이겠지.그것은 나에게 많은 시간을 절약해 주었다..net 소스 코드 디버깅을 활성화하려면 Shawn Bruke의 블로그를 참조하십시오.

  3. 마지막으로 ViewModel에서 포커스를 설정하기 위해 사용하는 일반적인 접근법은 Attached Properties입니다.저는 어떤 UILEment에서도 설정할 수 있는 매우 간단한 첨부파일을 작성했습니다.예를 들어 ViewModel의 속성 "IsFocused"에 바인딩할 수 있습니다.여기 있습니다.

     public static class FocusExtension
     {
         public static bool GetIsFocused(DependencyObject obj)
         {
             return (bool) obj.GetValue(IsFocusedProperty);
         }
    
         public static void SetIsFocused(DependencyObject obj, bool value)
         {
             obj.SetValue(IsFocusedProperty, value);
         }
    
         public static readonly DependencyProperty IsFocusedProperty =
             DependencyProperty.RegisterAttached(
                 "IsFocused", typeof (bool), typeof (FocusExtension),
                 new UIPropertyMetadata(false, OnIsFocusedPropertyChanged));
    
         private static void OnIsFocusedPropertyChanged(
             DependencyObject d, 
             DependencyPropertyChangedEventArgs e)
         {
             var uie = (UIElement) d;
             if ((bool) e.NewValue)
             {
                 uie.Focus(); // Don't care about false values.
             }
         }
     }
    

    이제 View(XAML)에서 이 속성을 ViewModel에 바인딩할 수 있습니다.

     <TextBox local:FocusExtension.IsFocused="{Binding IsUserNameFocused}" />
    

이 답변이 도움이 되지 않으면 2번을 참조하십시오.

지금까지 몇 천 번이고 답한 질문이지만, 저는 Anvaka의 기고문을 수정하여 저와 같은 문제를 안고 있는 다른 사람들에게 도움이 될 것이라고 생각합니다.

먼저 위의 Attached Property를 다음과 같이 변경하였습니다.

public static class FocusExtension
{
    public static readonly DependencyProperty IsFocusedProperty = 
        DependencyProperty.RegisterAttached("IsFocused", typeof(bool?), typeof(FocusExtension), new FrameworkPropertyMetadata(IsFocusedChanged){BindsTwoWayByDefault = true});

    public static bool? GetIsFocused(DependencyObject element)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }

        return (bool?)element.GetValue(IsFocusedProperty);
    }

    public static void SetIsFocused(DependencyObject element, bool? value)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }

        element.SetValue(IsFocusedProperty, value);
    }

    private static void IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var fe = (FrameworkElement)d;

        if (e.OldValue == null)
        {
            fe.GotFocus += FrameworkElement_GotFocus;
            fe.LostFocus += FrameworkElement_LostFocus;
        }

        if (!fe.IsVisible)
        {
            fe.IsVisibleChanged += new DependencyPropertyChangedEventHandler(fe_IsVisibleChanged);
        }

        if (e.NewValue != null && (bool)e.NewValue)
        {
            fe.Focus();
        }
    }

    private static void fe_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        var fe = (FrameworkElement)sender;
        if (fe.IsVisible && (bool)fe.GetValue(IsFocusedProperty))
        {
            fe.IsVisibleChanged -= fe_IsVisibleChanged;
            fe.Focus();
        }
    }

    private static void FrameworkElement_GotFocus(object sender, RoutedEventArgs e)
    {
        ((FrameworkElement)sender).SetValue(IsFocusedProperty, true);
    }

    private static void FrameworkElement_LostFocus(object sender, RoutedEventArgs e)
    {
        ((FrameworkElement)sender).SetValue(IsFocusedProperty, false);
    }
}

가시성 참조를 추가한 이유는 탭이었습니다.처음에 표시된 탭 이외의 다른 탭에서 첨부된 속성을 사용한 경우 수동으로 컨트롤의 초점을 맞출 때까지 연결된 속성은 작동하지 않았습니다.

또 다른 장애물은 초점을 잃었을 때 기본 속성을 false로 재설정하는 보다 우아한 방법을 만드는 것이었습니다.거기서 집중력 상실 이벤트가 발생했죠

<TextBox            
    Text="{Binding Description}"
    FocusExtension.IsFocused="{Binding IsFocused}"/>

시야 문제를 해결할 수 있는 더 좋은 방법이 있다면 알려주세요.

주의: Dependency Property에 BindsTwayByDefault를 삽입할 것을 제안해 주신 Apfelkuacha님 감사합니다.저는 오래 전에 제 코드로 그렇게 했지만, 이 게시물을 업데이트하지 않았습니다.이 변경으로 인해 WPF 코드에서는 Mode=TwoWay가 필요 없게 되었습니다.

가장 좋은 방법은 MVVM 원리를 깨끗하게 유지하는 것이라고 생각합니다.따라서 기본적으로 MVVM Light와 함께 제공되는 Messenger Class를 사용해야 하며 사용 방법은 다음과 같습니다.

뷰 모델(exampleViewModel.cs): 다음 기술

 Messenger.Default.Send<string>("focus", "DoFocus");

이제 View.cs(XAML이 아닌 view.xaml.cs)에서 컨스트럭터에 다음과 같이 적습니다.

 public MyView()
        {
            InitializeComponent();

            Messenger.Default.Register<string>(this, "DoFocus", doFocus);
        }
        public void doFocus(string msg)
        {
            if (msg == "focus")
                this.txtcode.Focus();
        }

이 방법은 코드를 줄이고 MVVM 표준을 유지하는 데 문제가 없습니다.

이 중 어느 것도 제게는 효과가 없었지만, 다른 사람들의 이익을 위해, 여기 제공된 코드 중 일부를 바탕으로 작성하게 되었습니다.

사용 방법은 다음과 같습니다.

<TextBox ... h:FocusBehavior.IsFocused="True"/>

구현은 다음과 같습니다.

/// <summary>
/// Behavior allowing to put focus on element from the view model in a MVVM implementation.
/// </summary>
public static class FocusBehavior
{
    #region Dependency Properties
    /// <summary>
    /// <c>IsFocused</c> dependency property.
    /// </summary>
    public static readonly DependencyProperty IsFocusedProperty =
        DependencyProperty.RegisterAttached("IsFocused", typeof(bool?),
            typeof(FocusBehavior), new FrameworkPropertyMetadata(IsFocusedChanged));
    /// <summary>
    /// Gets the <c>IsFocused</c> property value.
    /// </summary>
    /// <param name="element">The element.</param>
    /// <returns>Value of the <c>IsFocused</c> property or <c>null</c> if not set.</returns>
    public static bool? GetIsFocused(DependencyObject element)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }
        return (bool?)element.GetValue(IsFocusedProperty);
    }
    /// <summary>
    /// Sets the <c>IsFocused</c> property value.
    /// </summary>
    /// <param name="element">The element.</param>
    /// <param name="value">The value.</param>
    public static void SetIsFocused(DependencyObject element, bool? value)
    {
        if (element == null)
        {
            throw new ArgumentNullException("element");
        }
        element.SetValue(IsFocusedProperty, value);
    }
    #endregion Dependency Properties

    #region Event Handlers
    /// <summary>
    /// Determines whether the value of the dependency property <c>IsFocused</c> has change.
    /// </summary>
    /// <param name="d">The dependency object.</param>
    /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
    private static void IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        // Ensure it is a FrameworkElement instance.
        var fe = d as FrameworkElement;
        if (fe != null && e.OldValue == null && e.NewValue != null && (bool)e.NewValue)
        {
            // Attach to the Loaded event to set the focus there. If we do it here it will
            // be overridden by the view rendering the framework element.
            fe.Loaded += FrameworkElementLoaded;
        }
    }
    /// <summary>
    /// Sets the focus when the framework element is loaded and ready to receive input.
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
    private static void FrameworkElementLoaded(object sender, RoutedEventArgs e)
    {
        // Ensure it is a FrameworkElement instance.
        var fe = sender as FrameworkElement;
        if (fe != null)
        {
            // Remove the event handler registration.
            fe.Loaded -= FrameworkElementLoaded;
            // Set the focus to the given framework element.
            fe.Focus();
            // Determine if it is a text box like element.
            var tb = fe as TextBoxBase;
            if (tb != null)
            {
                // Select all text to be ready for replacement.
                tb.SelectAll();
            }
        }
    }
    #endregion Event Handlers
}

이것은 오래된 스레드이지만, Anavanka가 승인한 답변에 대한 코드의 답변은 없는 것 같습니다.뷰 모델에서 속성을 false로 설정하거나 속성을 true로 설정하면 사용자가 다른 항목을 수동으로 클릭한 다음 다시 true로 설정합니다.이러한 경우에서도 Zamotic의 솔루션이 안정적으로 작동하도록 할 수 없었습니다.

상기의 몇개의 논의를 정리하면, 이하의 코드로 이러한 문제를 해결할 수 있습니다.

public static class FocusExtension
{
    public static bool GetIsFocused(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsFocusedProperty);
    }

    public static void SetIsFocused(DependencyObject obj, bool value)
    {
        obj.SetValue(IsFocusedProperty, value);
    }

    public static readonly DependencyProperty IsFocusedProperty =
        DependencyProperty.RegisterAttached(
         "IsFocused", typeof(bool), typeof(FocusExtension),
         new UIPropertyMetadata(false, null, OnCoerceValue));

    private static object OnCoerceValue(DependencyObject d, object baseValue)
    {
        if ((bool)baseValue)
            ((UIElement)d).Focus();
        else if (((UIElement) d).IsFocused)
            Keyboard.ClearFocus();
        return ((bool)baseValue);
    }
}

그러나 코드 배후에 한 줄로 할 수 있는 작업으로는 아직 복잡하며, OrbceValue는 이러한 방식으로 사용할 수 없기 때문에 코드 배후에 사용할 수 있습니다.

내 경우 OnIsFocusPropertyChanged 메서드를 변경할 때까지 FocusExtension이 작동하지 않았습니다.원래 것은 중단점이 프로세스를 정지했을 때 디버깅으로만 동작하고 있었습니다.실행 시 프로세스가 너무 빨라서 아무 일도 일어나지 않습니다.이 약간의 수정과 친구 태스크의 도움으로 두 시나리오 모두 잘 작동합니다.

private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  var uie = (UIElement)d;
  if ((bool)e.NewValue)
  {
    var action = new Action(() => uie.Dispatcher.BeginInvoke((Action)(() => uie.Focus())));
    Task.Factory.StartNew(action);
  }
}

문제는 IsUserNameFocused가 true로 설정되면 절대 false가 되지 않는다는 것입니다.이를 위해 FrameworkElement용 GotFocus 및 LostFocus를 처리함으로써 문제를 해결합니다.

소스 코드 포맷에 문제가 있었으므로 여기 링크가 있습니다.

Anbakas brilliant code는 Windows Desktop 응용 프로그램용입니다.저와 마찬가지로 Windows Store 앱에 동일한 솔루션이 필요한 경우 이 코드가 유용할 수 있습니다.

public static class FocusExtension
{
    public static bool GetIsFocused(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsFocusedProperty);
    }


    public static void SetIsFocused(DependencyObject obj, bool value)
    {
        obj.SetValue(IsFocusedProperty, value);
    }


    public static readonly DependencyProperty IsFocusedProperty =
        DependencyProperty.RegisterAttached(
         "IsFocused", typeof(bool), typeof(FocusExtension),
         new PropertyMetadata(false, OnIsFocusedPropertyChanged));


    private static void OnIsFocusedPropertyChanged(DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        if ((bool)e.NewValue)
        {
            var uie = d as Windows.UI.Xaml.Controls.Control;

            if( uie != null )
            {
                uie.Focus(FocusState.Programmatic);
            }
        }
    }
}

@Sheridan 답변에 기초한 대체 접근법

 <TextBox Text="{Binding SomeText, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
        <TextBox.Style>
            <Style>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding SomeTextIsFocused, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Value="True">
                        <Setter Property="FocusManager.FocusedElement" Value="{Binding RelativeSource={RelativeSource Self}}" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBox.Style>
    </TextBox>

뷰 모델에서 일반적인 방법으로 바인딩을 설정한 후 SomeTextIsFocused를 true로 설정하여 텍스트 상자에 포커스를 설정합니다.

위의 Anvaka의 솔루션을 사용하려고 하는 분들을 위해 저는 처음에만 바인딩이 동작하는 것에 문제가 있었습니다. 왜냐하면 포커스를 잃으면 속성이 false로 갱신되지 않기 때문입니다.속성을 수동으로 false로 설정한 후 매번 true로 설정할 수 있지만 속성에서 다음과 같은 작업을 수행하는 것이 좋습니다.

bool _isFocused = false;
    public bool IsFocused 
    {
        get { return _isFocused ; }
        set
        {
            _isFocused = false;
            _isFocused = value;
            base.OnPropertyChanged("IsFocused ");
        }
    }

이렇게 하면 항상 true로 설정하기만 하면 초점이 맞춰집니다.

저는 WPF/Caliburn Micro를 사용하고 있습니다.dfaivre가 일반적이고 실용적인 솔루션을 만들었다는 것을 발견했습니다.http://caliburnmicro.codeplex.com/discussions/222892

Silverlight의 경우:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace MyProject.Behaviors
{
    public class FocusBehavior : Behavior<Control>
    {
        protected override void OnAttached()
        {
            this.AssociatedObject.Loaded += AssociatedObject_Loaded;
            base.OnAttached();
        }

        private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
        {
            this.AssociatedObject.Loaded -= AssociatedObject_Loaded;
            if (this.HasInitialFocus || this.IsFocused)
            {
                this.GotFocus();
            }
        }

        private void GotFocus()
        {
            this.AssociatedObject.Focus();
            if (this.IsSelectAll)
            {
                if (this.AssociatedObject is TextBox)
                {
                    (this.AssociatedObject as TextBox).SelectAll();
                }
                else if (this.AssociatedObject is PasswordBox)
                {
                    (this.AssociatedObject as PasswordBox).SelectAll();
                }
                else if (this.AssociatedObject is RichTextBox)
                {
                    (this.AssociatedObject as RichTextBox).SelectAll();
                }
            }
        }

        public static readonly DependencyProperty IsFocusedProperty =
            DependencyProperty.Register(
                "IsFocused",
                typeof(bool),
                typeof(FocusBehavior),
                new PropertyMetadata(false, 
                    (d, e) => 
                    {
                        if ((bool)e.NewValue)
                        {
                            ((FocusBehavior)d).GotFocus();
                        }
                    }));

        public bool IsFocused
        {
            get { return (bool)GetValue(IsFocusedProperty); }
            set { SetValue(IsFocusedProperty, value); }
        }

        public static readonly DependencyProperty HasInitialFocusProperty =
            DependencyProperty.Register(
                "HasInitialFocus",
                typeof(bool),
                typeof(FocusBehavior),
                new PropertyMetadata(false, null));

        public bool HasInitialFocus
        {
            get { return (bool)GetValue(HasInitialFocusProperty); }
            set { SetValue(HasInitialFocusProperty, value); }
        }

        public static readonly DependencyProperty IsSelectAllProperty =
            DependencyProperty.Register(
                "IsSelectAll",
                typeof(bool),
                typeof(FocusBehavior),
                new PropertyMetadata(false, null));

        public bool IsSelectAll
        {
            get { return (bool)GetValue(IsSelectAllProperty); }
            set { SetValue(IsSelectAllProperty, value); }
        }

    }
}

LoginViewModel.cs:

    public class LoginModel : ViewModelBase
    {
        ....

        private bool _EmailFocus = false;
        public bool EmailFocus
        {
            get
            {
                return _EmailFocus;
            }
            set
            {
                if (value)
                {
                    _EmailFocus = false;
                    RaisePropertyChanged("EmailFocus");
                }
                _EmailFocus = value;
                RaisePropertyChanged("EmailFocus");
            }
        }
       ...
   }

Login.xaml:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:beh="clr-namespace:MyProject.Behaviors"

<TextBox Text="{Binding Email, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    <i:Interaction.Behaviors>
        <beh:FocusBehavior IsFocused="{Binding EmailFocus}" IsSelectAll="True"/>
    </i:Interaction.Behaviors>
</TextBox>

또는

<TextBox Text="{Binding Email, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
    <i:Interaction.Behaviors>
        <beh:FocusBehavior HasInitialFocus="True" IsSelectAll="True"/>
    </i:Interaction.Behaviors>
</TextBox>

포커스를 설정하려면 , 다음의 코드로 실시합니다.

EmailFocus = true;

이 플러그인은 html 페이지의 일부이므로 페이지의 다른 컨트롤에 포커스가 있을 수 있습니다.

if (!Application.Current.IsRunningOutOfBrowser)
{
    System.Windows.Browser.HtmlPage.Plugin.Focus();
}

아래와 같이 코드를 편집하여 해결책을 찾았습니다.바인딩 속성을 먼저 False로 설정한 다음 True로 설정할 필요가 없습니다.

public static class FocusExtension
{

    public static bool GetIsFocused(DependencyObject obj)
    {
        return (bool)obj.GetValue(IsFocusedProperty);
    }


    public static void SetIsFocused(DependencyObject obj, bool value)
    {
        obj.SetValue(IsFocusedProperty, value);
    }


    public static readonly DependencyProperty IsFocusedProperty =
        DependencyProperty.RegisterAttached(
         "IsFocused", typeof(bool), typeof(FocusExtension),
         new UIPropertyMetadata(false, OnIsFocusedPropertyChanged));


    private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        if (d != null && d is Control)
        {
            var _Control = d as Control;
            if ((bool)e.NewValue)
            {
                // To set false value to get focus on control. if we don't set value to False then we have to set all binding
                //property to first False then True to set focus on control.
                OnLostFocus(_Control, null);
                _Control.Focus(); // Don't care about false values.
            }
        }
    }

    private static void OnLostFocus(object sender, RoutedEventArgs e)
    {
        if (sender != null && sender is Control)
        {
            (sender as Control).SetValue(IsFocusedProperty, false);
        }
    }
}

ViewCommand 설계 패턴을 사용할 수 있습니다.또한 명령을 사용하여 ViewModel에서 보기를 제어하는 MVVM 설계 패턴에 대한 방법을 설명합니다.

킹A를 기반으로 구현했습니다.Majid의 MVVM Light Messenger 클래스 사용 제안.ViewCommandManager 클래스는 연결된 뷰의 호출 명령을 처리합니다.ViewModel이 View에서 작업을 수행해야 하는 경우 기본적으로 일반 명령의 다른 방향입니다.데이터 바인딩 명령 및 WeakReferences와 같은 리플렉션을 사용하여 메모리 누수를 방지합니다.

http://dev.unclassified.de/source/viewcommand (Code Project에도 게재)

바인딩된 변수를 통해 속성을 쉽게 업데이트하기 위한 마지막 단계는 아무도 포함되지 않은 것 같습니다.내가 생각해낸 건 이거야더 좋은 방법이 있으면 알려주세요.

XAML

    <TextBox x:Name="txtLabel"
      Text="{Binding Label}"
      local:FocusExtension.IsFocused="{Binding txtLabel_IsFocused, Mode=TwoWay}" 
     />

    <Button x:Name="butEdit" Content="Edit"
        Height="40"  
        IsEnabled="{Binding butEdit_IsEnabled}"                        
        Command="{Binding cmdCapsuleEdit.Command}"                            
     />   

뷰 모델

    public class LoginModel : ViewModelBase
    {

    public string txtLabel_IsFocused { get; set; }                 
    public string butEdit_IsEnabled { get; set; }                


    public void SetProperty(string PropertyName, string value)
    {
        System.Reflection.PropertyInfo propertyInfo = this.GetType().GetProperty(PropertyName);
        propertyInfo.SetValue(this, Convert.ChangeType(value, propertyInfo.PropertyType), null);
        OnPropertyChanged(PropertyName);
    }                


    private void Example_function(){

        SetProperty("butEdit_IsEnabled", "False");
        SetProperty("txtLabel_IsFocused", "True");        
    }

    }

우선 나의 집중력 문제를 해결하도록 도와준 아반카에게 감사하고 싶다.그러나 그가 게시한 코드, 즉 if (e)에 버그가 있습니다.OldValue == null)

문제는 처음에 뷰를 클릭하여 컨트롤에 초점을 맞추면 e.oldValue가 null이 아니라는 것입니다.그런 다음 처음 컨트롤에 포커스를 맞추도록 변수를 설정하면 lostfocus 및 gotfocus 핸들러가 설정되지 않습니다.이에 대한 저의 해결책은 다음과 같습니다.

public static class ExtensionFocus
    {
    static ExtensionFocus()
        {
        BoundElements = new List<string>();
        }

    public static readonly DependencyProperty IsFocusedProperty =
        DependencyProperty.RegisterAttached("IsFocused", typeof(bool?),
        typeof(ExtensionFocus), new FrameworkPropertyMetadata(false, IsFocusedChanged));

    private static List<string> BoundElements;

    public static bool? GetIsFocused(DependencyObject element)
        {
        if (element == null)
            {
            throw new ArgumentNullException("ExtensionFocus GetIsFocused called with null element");
            }
        return (bool?)element.GetValue(IsFocusedProperty);
        }

    public static void SetIsFocused(DependencyObject element, bool? value)
        {
        if (element == null)
            {
            throw new ArgumentNullException("ExtensionFocus SetIsFocused called with null element");
            }
        element.SetValue(IsFocusedProperty, value);
        }

    private static void IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        var fe = (FrameworkElement)d;

        // OLD LINE:
        // if (e.OldValue == null)
        // TWO NEW LINES:
        if (BoundElements.Contains(fe.Name) == false)
            {
            BoundElements.Add(fe.Name);
            fe.LostFocus += OnLostFocus;
            fe.GotFocus += OnGotFocus;
            }           


        if (!fe.IsVisible)
            {
            fe.IsVisibleChanged += new DependencyPropertyChangedEventHandler(fe_IsVisibleChanged);
            }

        if ((bool)e.NewValue)
            {
            fe.Focus();             
            }
        }

    private static void fe_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
        var fe = (FrameworkElement)sender;

        if (fe.IsVisible && (bool)((FrameworkElement)sender).GetValue(IsFocusedProperty))
            {
            fe.IsVisibleChanged -= fe_IsVisibleChanged;
            fe.Focus();
            }
        }

    private static void OnLostFocus(object sender, RoutedEventArgs e)
        {
        if (sender != null && sender is Control s)
            {
            s.SetValue(IsFocusedProperty, false);
            }
        }

    private static void OnGotFocus(object sender, RoutedEventArgs e)
        {
        if (sender != null && sender is Control s)
            {
            s.SetValue(IsFocusedProperty, true);
            }
        }
    }

승인된 답변을 구현한 후 프리즘으로 뷰를 탐색할 때 TextBox에 포커스를 맞출 수 없다는 문제에 부딪혔습니다.PropertyChanged 핸들러의 사소한 변경으로 해결되었습니다.

    private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var uie = (UIElement)d;
        if ((bool)e.NewValue)
        {
            uie.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>
            {
                uie.Focus();
            }));
        }
    }

IsVisible 문제에 대한 Critical의 솔루션이 매우 유용하다는 을 알았습니다.문제가 완전히 해결되지는 않았지만 IsEnabled 패턴에 동일한 패턴을 따르는 추가 코드가 있었습니다.

추가한 IsFocused Changed 메서드에 대해:

    if (!fe.IsEnabled)
    {
        fe.IsEnabledChanged += fe_IsEnabledChanged;
    }

그리고 여기 핸들러가 있습니다.

private static void fe_IsEnabledChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    var fe = (FrameworkElement)sender;
    if (fe.IsEnabled && (bool)((FrameworkElement)sender).GetValue(IsFocusedProperty))
    {
        fe.IsEnabledChanged -= fe_IsEnabledChanged;
        fe.Focus();
    }
}
public class DummyViewModel : ViewModelBase
    {
        private bool isfocused= false;
        public bool IsFocused
        {
            get
            {
                return isfocused;
            }
            set
            {
                isfocused= value;
                OnPropertyChanged("IsFocused");
            }
        }
    }

다음 작업을 수행합니다.

<Window x:class...
   ...
   ...
   FocusManager.FocusedElement="{Binding ElementName=myTextBox}"
>
<Grid>
<TextBox Name="myTextBox"/>
...
System.Windows.Forms.Application.DoEvents();
Keyboard.Focus(tbxLastName);

언급URL : https://stackoverflow.com/questions/1356045/set-focus-on-textbox-in-wpf-from-view-model

반응형