Set focus on TextBox in WPF from view model Set focus on TextBox in WPF from view model wpf wpf

Set focus on TextBox in WPF from view model


Let me answer to your question in three parts.

  1. I'm wondering what is "cs.txtCompanyID" in your example? Is it a TextBox control? If yes, then you are on a wrong way. Generally speaking it's not a good idea to have any reference to UI in your ViewModel. You can ask "Why?" but this is another question to post on Stackoverflow :).

  2. The best way to track down issues with Focus is... debugging .Net source code. No kidding. It saved me a lot of time many times. To enable .net source code debugging refer to Shawn Bruke's blog.

  3. Finally, general approach that I use to set focus from ViewModel is Attached Properties. I wrote very simple attached property, which can be set on any UIElement. And it can be bound to ViewModel's property "IsFocused" for example. Here it is:

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

    Now in your View (in XAML) you can bind this property to your ViewModel:

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

Hope this helps :). If it doesn't refer to the answer #2.

Cheers.


I know this question has been answered a thousand times over by now, but I made some edits to Anvaka's contribution that I think will help others that had similar issues that I had.

Firstly, I changed the above Attached Property like so:

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

My reason for adding the visibility references were tabs. Apparently if you used the attached property on any other tab outside of the initially visible tab, the attached property didn't work until you manually focused the control.

The other obstacle was creating a more elegant way of resetting the underlying property to false when it lost focus. That's where the lost focus events came in.

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

If there's a better way to handle the visibility issue, please let me know.

Note: Thanks to Apfelkuacha for the suggestion of putting the BindsTwoWayByDefault in the DependencyProperty. I had done that long ago in my own code, but never updated this post. The Mode=TwoWay is no longer necessary in the WPF code due to this change.


I think the best way is to keep the MVVM principle clean,so basically you must use the Messenger Class provided with the MVVM Light and here is how to use it:

in your viewmodel(exampleViewModel.cs):write the following

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

now in your View.cs(not the XAML the view.xaml.cs) write the following in the constructor

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

that method owrks just fine and with less code and maintaining MVVM standards