147

I have a TextBox and a Button in my view.

Now I am checking a condition upon button click and if the condition turns out to be false, displaying the message to the user, and then I have to set the cursor to the TextBox control.

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

The above code is in the ViewModel.

The CompanyAssociation is the view name.

But the cursor is not getting set in the TextBox.

The xaml is:

<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}"/>
ASh
  • 34,632
  • 9
  • 60
  • 82
priyanka.sarkar
  • 25,766
  • 43
  • 127
  • 173
  • When you are using caliburn.micro [this](https://stackoverflow.com/a/20936288/932328) is an excellent solution. – matze8426 Jul 31 '18 at 10:01

21 Answers21

300

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

If this answer doesn't help, refer to the answer #2.

starball
  • 20,030
  • 7
  • 43
  • 238
Anvaka
  • 15,658
  • 2
  • 47
  • 56
  • 9
    Cool idea. I need to set IsUserNameFocused to true, then false again to get this working, is this right? – Sam Apr 19 '10 at 14:19
  • Thank you Sam. It depends. Sometimes it's enough to set it to true only once. – Anvaka Apr 21 '10 at 10:45
  • @Anvaka how do you do the binding in your view model? is it a property or an ICommand or somthing else, I can't seem to get my head around this bit. – Rob Aug 12 '11 at 08:50
  • @Rob it's just a property, named "IsUserNameFocused". – Anvaka Aug 12 '11 at 17:48
  • 23
    You should also call `Keyboard.Focus(uie);` from your `OnIsFocusedPropertyChanged` event if you want your control to receive Keyboard Focus as well as Logical Focus – Rachel Oct 10 '11 at 18:14
  • 9
    How is this supposed to be used? If I set my property to true, the control is focused. But it will always be focused again when I come back to this view. Resetting it from OnIsFocusedPropertyChanged doesn't change this. Resetting it directly after setting it from the ViewModel does not focus anything anymore. It doesn't work. What have those 70 upvoters done exactly? – ygoe Feb 26 '13 at 23:02
  • 1
    @Anvaka i tryed something based on this solution but i got stucked please take a look at it [Click HERE](http://stackoverflow.com/questions/16964886/how-to-focus-an-textbox-on-button-click) – WiiMaxx Jun 06 '13 at 14:36
  • 2
    I wrestled with setting the focus of a textbox in a dialog I display in a WPF application displaying the dialog as a UserControl. I managed to finally make the focusing working, after trying out many different approaches. Your code above worked after I adjusted it to use Dispatcher.CurrentDispatcher.BeginInvoke to do the Focus call: Dispatcher.CurrentDispatcher.BeginInvoke((Action)(() => { uie.Focus(); //Don't care about false values })); – Tore Aurstad Jun 19 '13 at 08:58
  • 3
    you can change `obj.SetValue(IsFocusedProperty, value);` to `obj.SetValue(IsFocusedProperty, false);` and not have to set false and true again. – Owen Johnson Aug 21 '13 at 21:05
  • 5
    I also changed the callback to this: `...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 ...` Sometimes I even have to reset the 'IsFocused' to false in the ViewModel, if I want to set the focus multiple times. But then it works, where some other methods failed. – Simon D. Sep 30 '13 at 09:29
  • This worked beautifully for me. I'm using Visual Studio 2013 / MVVM Light. To effectively remove the visible focus from all textboxes, you can set the focus to something like a TextBlock which isn't normally editable. – Contango Oct 09 '14 at 15:23
  • 3
    after you set the focus and another control gets the focus, to set the focus again won't work because IsFocused is still true. Need to force it to false and then true. `public bool IsFocused { get { return _isFocused; } set { if (_isFocused == value) { _isFocused = false; OnPropertyChanged(); } _isFocused = value; OnPropertyChanged(); } }` – walterhuang Jun 29 '18 at 17:36
89

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.

Ian Kemp
  • 28,293
  • 19
  • 112
  • 138
Zamotic
  • 1,127
  • 8
  • 12
  • 11
    This works well for me except I need to add a "if (e.Source == e.OriginalSource)" check in the GotFocus/LostFocus or else it stackoverflows (literally) when used on my UserControl, which does redirect the focus to inner component. I removed the Visible checks, accepting the fact that it works just like .Focus() method. If .Focus() doesn't work, the binding shouldn't work - and that's ok for my scenario. – HelloSam Mar 22 '13 at 20:08
  • YOU ABSOLUTE GENIUS. Spent a whole day on this. Thanks!! I have been trying to find a way to focus an element and hide it when it doesn't have focus. But this really screws up the dependency properties. This solution worked for me. – Asheh Nov 27 '14 at 18:14
  • 1
    I am using this in WF 4.5. On IsFocusedChanged i have a scenario (an Activity gets reloaded ) where e.NewValue is null and throws a exception so check that first. Everything works fine with this minor change. – Olaru Mircea Apr 24 '15 at 09:05
  • 1
    Thanks this wprks Great :) I just added ' {BindsTwoWayByDefault = true}' at 'FrameworkPropertyMetadata' to set the default mode to TwoWayBinding so it is not needed on every Binding – R00st3r Oct 11 '16 at 09:04
  • 1
    I realize this is an old answer, but I'm running into a situation where the IsEnabled property of the control I want to shift the focus to is tied to a multi-value converter. Apparently, the GotFocus event handler gets called before the multi-value converter does...which means the control, at that point, is disabled, so as soon as GotFocus completes, LostFocus gets called (I guess because the control is still disabled). Any thoughts on how to handle that? – Mark Olbert Mar 20 '18 at 15:37
  • 1
    @MarkOlbert use `fe.Dispatcher.BeginInvoke(new Action(() => { fe.Focus(); }), DispatcherPriority.Loaded);` that it is updated after it is loaded. More info here: https://www.telerik.com/forums/isfocused-property#OXgFYZFOg0WZ2rxidln61Q – Coden Oct 23 '18 at 08:56
  • Very good solution, helped a lot. Only problem that I had was when I returned from one window to another it threw null exception so I added check for null in `if (e.NewValue != null && (bool)e.NewValue)` and now works well – Daniel Žeimo Dec 10 '18 at 11:50
  • This doesn't work for me. When I try it, the control gets the focus but doesn't show the caret. Or maybe it's losing the focus and not showing it for that reason, but either way the focus doesn't go to the right place. – Joshua Frank Aug 26 '19 at 19:09
  • this solution is easier to use in the viewModel. Just set the bound property to true once. after that reusing Notify property change on the property will get it into focus again. The accepted answer instead would need set true -> notify -> set false -> notify every time, which is quite annoying. the more i have to work with wpf mvvm, the more i love the time with win forms and code behind... single line solutions where so awesome.. – Welcor Oct 27 '19 at 16:29
  • while this works better in viewModel, it crashes when comboBox with isEditable=true is used. the accepted answer does not crash in this case – Welcor Oct 28 '19 at 15:22
35

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

Adam
  • 3,815
  • 29
  • 24
  • 9
    Well if you want to keep the MVVM principle clean, you wouldn't be writing code in your code behind in the first place. I believe the attached property approach is much cleaner. It doesn't introduce a lot of magic strings in your view model as well. – Ε Г И І И О Mar 15 '12 at 21:15
  • 40
    El Nino: Where exactly did you get the idea there shouldn't be anything in your view code-behind? Anything that is UI-related should be in the view's code-behind. Setting focus of UI elements should *Definitely* be in the view's code-behind. Let the viewmodel figure out when to send the message; let the view figure out what to do with the message. *That* is what M-V-VM does: separates the concerns of data model, business logic, and UI. – Kyle Hale Feb 19 '13 at 05:00
  • Based on this suggestion, I've implemented my own ViewCommandManager that handles invoking commands in connected views. It's basically the other direction of regular Commands, for these cases when a ViewModel needs to do some action in its View(s). It uses reflection like data-bound commands and WeakReferences to avoid memory leaks. http://dev.unclassified.de/source/viewcommand (also on CodeProject) – ygoe Feb 01 '14 at 11:50
  • I used this method to print out WPF FlowDocuments. Worked nicely. Thanks – Gordon Slysz May 02 '14 at 20:35
  • I want one in Silverlight? Can we use it? – Bigeyes Jan 06 '17 at 19:13
  • Although it is good to know how to make use of dependency injection from view model, I think sending out the message (this solution) is more straight forward and easy. – scsfdev Nov 01 '17 at 01:51
  • I used this in a pure MVVM solution. Works great, thanks – Michael K Oct 17 '18 at 02:21
  • the best crutch! – Stepagrus Dec 28 '22 at 07:20
17

This is an old thread, but there doesn't seem to be an answer with code that addresses the issues with Anavanka's accepted answer: it doesn't work if you set the property in the viewmodel to false, or if you set your property to true, the user manually clicks on something else, and then you set it to true again. I couldn't get Zamotic's solution to work reliably in these cases either.

Pulling together some of the discussions above gives me the code below which does address these issues I think:

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

Having said that, this is still complex for something that can be done in one line in codebehind, and CoerceValue isn't really meant to be used in this way, so maybe codebehind is the way to go.

Rich N
  • 8,939
  • 3
  • 26
  • 33
17

None of these worked for me exactly, but for the benefit of others, this is what I ended up writing based on some of the code already provided here.

Usage would be as follows:

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

And the implementation would be as follows:

/// <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
}
Leo Vildosola
  • 179
  • 1
  • 2
5

In my case, the FocusExtension didn't work until I change the method OnIsFocusedPropertyChanged. The original one was working only in debug when a break point stopped the process. At runtime, the process is too quick and nothing happend. With this little modification and the help of our friend Task, this is working fine in both scenarios.

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

Anvakas brilliant code is for Windows Desktop applications. If you are like me and needed the same solution for Windows Store apps this code might be handy:

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);
            }
        }
    }
}
PEK
  • 3,688
  • 2
  • 31
  • 49
3

The problem is that once the IsUserNameFocused is set to true, it will never be false. This solves it by handling the GotFocus and LostFocus for the FrameworkElement.

I was having trouble with the source code formatting so here is a link

Shawn
  • 31
  • 2
  • 1
    I chhanged "object fe = (FrameworkElement)d;" to "FrameworkElement fe = (FrameworkElement)d;" so the intellisense works –  Jan 29 '13 at 14:15
  • Still doesn't solve the problem. The element stays focused every time I come back to it. – ygoe Feb 26 '13 at 23:11
3

An alternative approach based on @Sheridan answer here

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

In your view model set up your binding in the usual way and then set the SomeTextIsFocused to true to set the focus on your text box

stuicidle
  • 297
  • 1
  • 8
1

I use WPF / Caliburn Micro a found that "dfaivre" has made a general and workable solution here: http://caliburnmicro.codeplex.com/discussions/222892

kpp
  • 11
  • 2
1

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

OR

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

To set the focus should just do it in code:

EmailFocus = true;

Remember that this plugin is part of an html page, so other controls in the page might have the focus

if (!Application.Current.IsRunningOutOfBrowser)
{
    System.Windows.Browser.HtmlPage.Plugin.Focus();
}
ADM-IT
  • 3,719
  • 1
  • 25
  • 26
1

I have found solution by editing code as per following. There is no need to set Binding property first False then 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);
        }
    }
}
1

For those trying to use Anvaka's solution above, I was having issues with the binding only working the first time, as lostfocus would not update the property to false. You can manually set the property to false and then true every time, but a better solution could be to do something like this in your property:

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

This way you only ever need to set it to true, and it will get focus.

Wai Ha Lee
  • 8,598
  • 83
  • 57
  • 92
Kyeotic
  • 19,697
  • 10
  • 71
  • 128
  • Why have you a if statement? the _isFocused once set to false will just be changed to value on the next line. – Damien McGivern Oct 07 '11 at 09:13
  • 1
    @Tyrsius You can round this issue by getting the dependency property to Coerce, see here- http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/d79f8b34-e116-45f7-a592-42d6b849a437/ – RichardOD Feb 17 '12 at 15:20
0

You could use the ViewCommand design pattern. It describes a method for the MVVM design pattern to control a View from a ViewModel with commands.

I've implemented it based on King A.Majid's suggestion to use the MVVM Light Messenger class. The ViewCommandManager class handles invoking commands in connected views. It's basically the other direction of regular Commands, for these cases when a ViewModel needs to do some action in its View. It uses reflection like data-bound commands and WeakReferences to avoid memory leaks.

http://dev.unclassified.de/source/viewcommand (also published on CodeProject)

ygoe
  • 18,655
  • 23
  • 113
  • 210
0

Nobody seems to have included the final step to make it easy to update attributes via binded variables. Here's what I came up with. Let me know if there is a better way of doing this.

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

ViewModel

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

    }
Hugh
  • 175
  • 2
  • 2
0

First off i would like to thank Avanka for helping me solve my focus problem. There is however a bug in the code he posted, namely in the line: if (e.OldValue == null)

The problem I had was that if you first click in your view and focus the control, e.oldValue is no longer null. Then when you set the variable to focus the control for the first time, this results in the lostfocus and gotfocus handlers not being set. My solution to this was as follows:

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

After implementing the accepted answer I did run across an issue that when navigating views with Prism the TextBox would still not get focus. A minor change to the PropertyChanged handler resolved it

    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();
            }));
        }
    }
Joe H
  • 584
  • 3
  • 14
-1
public class DummyViewModel : ViewModelBase
    {
        private bool isfocused= false;
        public bool IsFocused
        {
            get
            {
                return isfocused;
            }
            set
            {
                isfocused= value;
                OnPropertyChanged("IsFocused");
            }
        }
    }
Huy Nghia
  • 996
  • 8
  • 22
Jayasri
  • 237
  • 1
  • 11
-1

Just do this:

<Window x:class...
   ...
   ...
   FocusManager.FocusedElement="{Binding ElementName=myTextBox}"
>
<Grid>
<TextBox Name="myTextBox"/>
...
Zoltan
  • 137
  • 10
-1

I found Crucial's solution to the IsVisible problem very useful. It didn't completely solve my problem, but some extra code following the same pattern for the IsEnabled pattern did.

To the IsFocusedChanged method I added:

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

And here's the handler:

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();
    }
}
Community
  • 1
  • 1
Wayne Maurer
  • 12,333
  • 4
  • 33
  • 43
-7
System.Windows.Forms.Application.DoEvents();
Keyboard.Focus(tbxLastName);
Jason Plank
  • 2,336
  • 5
  • 31
  • 40
KitWest
  • 1
  • 1