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


129

나는이 TextBox과를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}"/>

당신이 caliburn.micro 사용하는 경우 이하는 훌륭한 솔루션입니다.
matze8426

답변:


264

세 부분으로 귀하의 질문에 대답하겠습니다.

  1. 귀하의 예에서 "cs.txtCompanyID"가 무엇인지 궁금합니다. TextBox 컨트롤입니까? 그렇다면, 당신은 잘못된 길을 가고 있습니다. 일반적으로 ViewModel에서 UI에 대한 참조를 갖는 것은 좋지 않습니다. "왜?" 그러나 이것은 Stackoverflow :)에 게시해야 할 또 다른 질문입니다.

  2. Focus 관련 문제를 추적하는 가장 좋은 방법은 .Net 소스 코드를 디버깅하는 것입니다. 농담이 없습니다. 많은 시간을 절약했습니다. .net 소스 코드 디버깅을 활성화하려면 Shawn Bruke의 블로그를 참조하십시오 .

  3. 마지막으로 ViewModel에서 포커스를 설정하는 데 사용하는 일반적인 방법은 첨부 속성입니다. UIElement에 설정할 수있는 매우 간단한 첨부 속성을 작성했습니다. 예를 들어 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.
            }
        }
    }

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

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

도움이 되었기를 바랍니다 :). 답변 # 2를 참조하지 않는 경우.

건배.


5
멋진 생각. IsUserNameFocused를 true로 설정 한 다음이 작업을 수행하려면 다시 false를 설정해야합니다. 맞습니까?
Sam

19
컨트롤이 논리 포커스뿐만 아니라 키보드 포커스를 받도록하려면 이벤트 Keyboard.Focus(uie);에서 전화해야합니다.OnIsFocusedPropertyChanged
Rachel

6
이것은 어떻게 사용됩니까? 내 속성을 true로 설정하면 컨트롤에 초점이 맞춰집니다. 그러나이 견해로 돌아 오면 항상 다시 초점을 맞출 것입니다. OnIsFocusedPropertyChanged에서 재설정해도 변경되지 않습니다. ViewModel에서 설정 한 후 바로 재설정하면 더 이상 초점이 맞지 않습니다. 작동하지 않습니다. 70 명의 지지자들은 정확히 무엇을 했습니까?
ygoe

4
또한 콜백을 다음과 같이 변경했습니다 ...if ((bool)e.NewValue && uie.Dispatcher != null) { uie.Dispatcher.BeginInvoke(DispatcherPriority.Normal, (Action)(() => uie.Focus())); // invoke behaves nicer, if e.g. you have some additional handler attached to 'GotFocus' of UIE. uie.SetValue(IsFocusedProperty, false); // reset bound value if possible, to allow setting again ... . 포커스를 여러 번 설정하려면 ViewModel에서 'IsFocused'를 false로 재설정 해야하는 경우가 있습니다. 그러나 다른 방법이 실패한 곳에서는 작동합니다.
Simon D.

3
포커스를 설정하고 다른 컨트롤에서 포커스를 얻은 후에는 IsFocused가 여전히 true이므로 포커스를 다시 설정해도 작동하지 않습니다. 강제로 거짓으로 설정 한 다음 사실로 설정해야합니다. public bool IsFocused { get { return _isFocused; } set { if (_isFocused == value) { _isFocused = false; OnPropertyChanged(); } _isFocused = value; OnPropertyChanged(); } }
walterhuang

75

나는이 질문이 지금까지 천 번 이상 대답되었다는 것을 알고 있지만, 비슷한 문제가있는 다른 사람들을 도울 것으로 생각되는 Anvaka의 기여를 약간 수정했습니다.

먼저 위의 첨부 속성을 다음과 같이 변경했습니다.

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 ((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 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);
    }
}

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

다른 장애물은 기본 속성이 포커스를 잃었을 때 거짓으로 재설정하는보다 우아한 방법을 만드는 것이 었습니다. 이곳에서 잃어버린 초점 이벤트가 시작되었습니다.

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

가시성 문제를 처리하는 더 좋은 방법이 있으면 알려주세요.

참고 : BindsTwoWayByDefault를 DependencyProperty에 넣을 것을 제안한 Apfelkuacha에게 감사드립니다. 나는 오래 전에 내 자신의 코드로 수행했지만이 게시물을 업데이트하지 않았습니다. 이 변경으로 인해 WPF 코드에서 더 이상 Mode = TwoWay가 필요하지 않습니다.


9
이것은 GotFocus / LostFocus에 "if (e.Source == e.OriginalSource)"검사를 추가하거나 내 UserControl에서 포커스를 내부로 리디렉션하는 스택 오버 플로우 (문자 그대로)를 추가해야한다는 점을 제외하고는 잘 작동합니다. 구성 요소. Visible 검사를 제거하고 .Focus () 메서드와 동일하게 작동한다는 사실을 인정했습니다. .Focus ()가 작동하지 않으면 바인딩이 작동하지 않아야합니다. 제 시나리오에는 괜찮습니다.
HelloSam

1
WF 4.5에서 이것을 사용하고 있습니다. IsFocusedChanged에서 e.NewValue가 null이고 예외를 throw하는 시나리오가 있습니다 (활동이 다시로드됩니다). 먼저 확인하십시오. 이 작은 변화로 모든 것이 잘 작동합니다.
Olaru Mircea

1
감사합니다. wprks Great :) 방금 'FrameworkPropertyMetadata'에 '{BindsTwoWayByDefault = true}'를 추가하여 기본 모드를 TwoWayBinding으로 설정하여 모든 바인딩에 필요하지는 않습니다.
R00st3r

1
나는 이것이 오래된 대답이라는 것을 알고 있지만 포커스를 이동하려는 컨트롤의 IsEnabled 속성이 다중 값 변환기에 묶여있는 상황에 처해 있습니다. 분명히 다중 값 변환기가 수행되기 전에 GotFocus 이벤트 핸들러가 호출됩니다 ... 즉, 그 시점에서 제어가 비활성화되어 GotFocus가 완료되는 즉시 LostFocus가 호출됩니다 (제어가 여전히 비활성화되어 있기 때문에 추측합니다) . 그것을 처리하는 방법에 대한 생각이 있습니까?
Mark Olbert

1
@MarkOlbert fe.Dispatcher.BeginInvoke(new Action(() => { fe.Focus(); }), DispatcherPriority.Loaded);는로드 된 후에 업데이트된다는 것을 사용 합니다. 여기에 더 많은 정보 : telerik.com/forums/isfocused-property#OXgFYZFOg0WZ2rxidln61Q
Apfelkuacha

32

가장 좋은 방법은 MVVM 원칙을 깨끗하게 유지하는 것이므로 기본적으로 MVVM Light와 함께 제공된 메신저 클래스를 사용해야하며 사용 방법은 다음과 같습니다.

viewmodel (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 표준을 유지하면서도 훌륭합니다.


9
MVVM 원칙을 깨끗하게 유지하려면 먼저 코드에 코드를 작성하지 않아도됩니다. 첨부 된 부동산 접근 방식이 훨씬 깨끗하다고 ​​생각합니다. 뷰 모델에 많은 마술 문자열을 소개하지는 않습니다.
Ε Г И І И О

32
El Nino : 뷰 코드 뒤에 아무것도 없어야한다는 아이디어를 정확히 어디서 얻었습니까? UI와 관련된 것은 뷰의 코드 숨김에 있어야합니다. UI 요소의 초점을 설정해야 확실히 뷰의 코드 숨김에서합니다. 뷰 모델이 언제 메시지를 보낼지 알아 내도록하자. 보기가 메시지와 함께 수행 할 작업을 파악하도록하십시오. 이것이 바로 MV-VM이하는 일입니다. 데이터 모델, 비즈니스 로직 및 UI의 문제를 구분합니다.
Kyle Hale

이 제안에 따라 연결된 뷰에서 명령 호출을 처리하는 자체 ViewCommandManager를 구현했습니다. 기본적으로 일반 명령의 다른 방향입니다. 이러한 경우 ViewModel이 View에서 일부 작업을 수행해야하는 경우입니다. 데이터 바운드 명령 및 WeakReferences와 같은 리플렉션을 사용하여 메모리 누수를 방지합니다. dev.unclassified.de/source/viewcommand (또한 CodeProject)
ygoe

이 방법을 사용하여 WPF FlowDocuments를 인쇄했습니다. 잘 작동했습니다. 감사합니다
Gordon Slysz

Silverlight에서 원하십니까? 사용할 수 있습니까?
Bigeyes

18

이것들 중 어느 것도 나를 위해 정확하게 일한 것은 아니지만 다른 사람들의 이익을 위해 이미 여기에 제공된 코드 중 일부를 기반으로 작성했습니다.

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

<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
}

11

이것은 오래된 스레드이지만 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);
    }
}

그럼에도 불구하고 이것은 여전히 ​​코드 숨김에서 한 줄로 수행 할 수있는 무언가에 대해 복잡하며 CoerceValue는 실제로 이런 식으로 사용되도록 의도되지 않았으므로 코드 숨김이 갈 길입니다.


1
이것은 일관되게 작동하지만 허용되는 대답은 그렇지 않습니다. 감사!
NathanAldenSr

4

필자의 경우 OnIsFocusedPropertyChanged 메서드를 변경할 때까지 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);
  }
}

3

문제는 IsUserNameFocused가 true로 설정되면 false가되지 않는다는 것입니다. 이를 통해 FrameworkElement의 GotFocus 및 LostFocus를 처리하여 문제를 해결합니다.

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


1
"object fe = (FrameworkElement) d;"를 변경했습니다. "FrameworkElement fe = (FrameworkElement) d;" IntelliSense를 작품 때문에

여전히 문제가 해결되지 않습니다. 내가 돌아올 때마다 요소가 계속 집중됩니다.
ygoe

3

Anvakas 화려한 코드는 Windows 데스크톱 응용 프로그램을위한 것입니다. 나와 비슷하고 Windows 스토어 앱에 대해 동일한 솔루션이 필요한 경우이 코드가 유용 할 수 있습니다.

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);
            }
        }
    }
}

1

위의 Anvaka 솔루션을 사용하려는 사람들에게는 lostfocus가 속성을 false로 업데이트하지 않기 때문에 바인딩이 처음으로 작동하는 데 문제가있었습니다. 매번 속성을 false로 설정 한 다음 true로 설정할 수 있지만 더 좋은 해결책은 속성에서 다음과 같은 작업을 수행하는 것입니다.

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

이 방법으로 당신은 그것을 true로 설정하기 만하면되고 초점을 맞출 것입니다.


왜 당신은 if 문을 가지고 있습니까? false로 설정된 _isFocused는 다음 줄의 value로 변경됩니다.
Damien McGivern

1
@Tyrsius 종속성 속성을 Coerce로 가져와이 문제를 해결할 수 있습니다. 여기를 참조하십시오. social.msdn.microsoft.com/Forums/en-US/wpf/thread/…
RichardOD


1

다음과 같이 코드를 편집하여 솔루션을 찾았습니다. 바인딩 속성을 먼저 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);
        }
    }
}

0

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();
}

0

ViewCommand를 사용할 수 있습니다 디자인 패턴을 . MVVM 디자인 패턴이 명령으로 ViewModel에서 View를 제어하는 ​​방법에 대해 설명합니다.

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

http://dev.unclassified.de/source/viewcommand(CodeProject 에도 게시 됨)


0

바인드 된 변수를 통해 속성을 쉽게 업데이트 할 수 있도록 마지막 단계를 포함하지 않은 것 같습니다. 여기에 내가 생각해 낸 것이 있습니다. 더 좋은 방법이 있는지 알려주세요.

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");        
    }

    }

0

먼저 초점 문제를 해결하는 데 도움을 준 Avanka에게 감사의 말씀을 전합니다. 그러나 그가 게시 한 코드에는 버그가 있습니다 : if (e.OldValue == null)

내가 가진 문제는 처음보기를 클릭하고 컨트롤에 초점을 맞추면 e.oldValue가 더 이상 null이 아니라는 것입니다. 그런 다음 컨트롤에 처음으로 초점을 맞추도록 변수를 설정하면 로스트 포커스 및 getfocus 처리기가 설정되지 않습니다. 이것에 대한 나의 해결책은 다음과 같습니다.

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);
            }
        }
    }

0

그냥 이렇게 :

<Window x:class...
   ...
   ...
   FocusManager.FocusedElement="{Binding ElementName=myTextBox}"
>
<Grid>
<TextBox Name="myTextBox"/>
...

나는 이것을 좋아한다. 초기 초점을 설정하려는 경우 잘 작동합니다.
user2430797

0

수락 된 답변을 구현 한 후 Prism으로 뷰를 탐색 할 때 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();
            }));
        }
    }

0

@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로 설정하여 텍스트 상자에 초점을 설정하십시오.


-1

Crucial을 찾았습니다IsVisible 문제에 대한 의 솔루션이 매우 유용하다는 . 그것은 내 문제를 완전히 해결하지는 못했지만 IsEnabled 패턴과 동일한 패턴을 따르는 추가 코드가 있습니다.

IsFocusedChanged 메소드에 다음을 추가했습니다.

    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();
    }
}

-1
public class DummyViewModel : ViewModelBase
    {
        private bool isfocused= false;
        public bool IsFocused
        {
            get
            {
                return isfocused;
            }
            set
            {
                isfocused= value;
                OnPropertyChanged("IsFocused");
            }
        }
    }

-7
System.Windows.Forms.Application.DoEvents();
Keyboard.Focus(tbxLastName);

1
OP는 WPF를 사용하고 있습니다. WinForms의 포커스 코드는 도움이되지 않습니다.
Josh G
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.