17

How to focus a textbox from ViewModel wpf?

<TextBox Name="PropertySearch"
         Text="{Binding UpdateSourceTrigger=PropertyChanged, 
                        Mode=TwoWay, Path=PropertySearch, 
                        ValidatesOnDataErrors=True}"  
         Width="110" 
         Height="25" 
         Margin="10" />
Askolein
  • 3,250
  • 3
  • 28
  • 40
Nivid Dholakia
  • 5,272
  • 4
  • 30
  • 55
  • 10
    The ViewModel cares not who has and who does not have focus. That is the purview of the View. –  Jul 18 '11 at 19:05

4 Answers4

49

You can do this by adding a property to your ViewModel (or use an existing property) that indicates when the SetFocus should happen but the View should be responsible for actually setting the focus since that is purely View related.

You can do this with a DataTrigger.

View:

<Grid Name="LayoutRoot" DataContext="{StaticResource MyViewModelInstance}">
    <Grid.Style>
        <Style>
            <Style.Triggers>
                <DataTrigger Binding="{Binding UserShouldEditValueNow}" Value="True">
                    <Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=PropertySearch}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Grid.Style>
    <TextBox   Name="PropertySearch"   Text="{Binding UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, Path=PropertySearch, ValidatesOnDataErrors=True}" Width="110" Height="25" Margin="10" />
</Grid>

ViewModel:

// When you think the view should set focus on a control
this.UserShouldEditValueNow = true;

The example above is simplified by just using a boolean ViewModel property "UserShouldEditValueNow". You can add a property like this to your ViewModel or use some other exising property that indicates this state.

Note: So why is it done this way in MVVM? One reason is, suppose the View author decided to replace the TextBox with a ComboBox, or even better, suppose your property was an integer value that had both a TextBox to view/edit the number and a Slider as another way to edit the same value, both controls bound to the same property... how would the ViewModel know which control to set focus on? (when it shouldn't even know what control, or controls, are bound to it in the first place) This way the View can select which control to focus by changing the ElementName binding target in the DataTrigger Setter.

Happy coding!

Harlow Burgess
  • 1,876
  • 14
  • 12
  • 14
    I find it even better to put the style directly inside the control to be focused and to bind the setter with `{RelativeSource Mode=Self}` to avoid the ElementName. – igelineau Jun 02 '14 at 20:11
  • This is for WPF. Do you have a solution for Silverlight? – Bigeyes Jan 06 '17 at 14:31
  • 1
    FYI, this is not a complete solution since the focus cannot be kept in the TextBox. The issue I experienced is that if the keyboard focus is lost due to clicking something else the cursor still flashes in the text box in addition to where ever else I click which is very confusing. So keep in mind that you'll probably have to deal with that somehow with some other command linked to a lost focus event. However, the xaml was very helpful so thank you for that. It is much simpler than the other attached property solutions that I have read. – shawn1874 Jan 08 '18 at 18:04
  • 1
    To take it further, I've discovered that the issue with this pattern has to do with keyboard focus vs logical focus. At times, the textbox ends up with logical focus and has the flashing cursor but it does me no good because it doesn't have keyboard focus which is more important for data entry. That's kind of the whole point of making the text box have focus. – shawn1874 Jan 08 '18 at 19:51
  • I have used same code but not working for me. Please help. – Jayakrishnan Jan 24 '19 at 11:54
10

The question you should be asking yourself is "why does my ViewModel need to know which control has the focus?"

I'd argue for focus being a view-only property; it's an interaction property, and has nothing to do with the conceptual state. This is akin to the background color of a control: why would you represent it in the VM? If you need to manage the focus in a custom way, it's probably better to use a view-level object to do the job.

Ben Straub
  • 5,675
  • 3
  • 28
  • 43
  • 8
    This isn't a helpful answer. How exactly would the business logic communicate to the view object that you propose? The point is that something in the system occurs causing a need for the focus to be set into some control. The OP is using the MVVM pattern. Therefore in the MVVM pattern what is the best approach to getting the focus set in a way that allows the various pieces to communicate. Your answer provides no guidance whatsoever. – shawn1874 Jan 08 '18 at 18:07
4

In your parent control, add the following property:

FocusManager.FocusedElement="{Binding ElementName=PropertySearch}" 
Nick Heidke
  • 2,787
  • 2
  • 34
  • 58
  • The Thing is it will set it on load. but the thing is i have key mappings in my application that i handle it through viewmodels so when particualar key is pressed supposed ctrl+f then it should focus the textbox. – Nivid Dholakia Jul 18 '11 at 19:02
  • As will alludes to above, the viewmodel shouldn't be concerned with the workings of the view. Your easiest route here is to put this type of functionality in the code behind. – Nick Heidke Jul 18 '11 at 19:15
  • I found out a workaround for that. Thanks for the answers.It can be accomplished by messaging the view to focus the element. – Nivid Dholakia Jul 18 '11 at 19:56
1

While purists may argue for leaving this out of the VM, there are cases where it may make sense to do so from the VM.

My approach has been to make the view implement an interface, pass that interface to the ViewModel, and then let the VM call methods on the interface.

Example:

public interface IFocusContainer
{
   void SetFocus(string target);
}

A couple things to keep in mind:

  1. A VM might serve more than one instance of a view, so your VM might want to have a collection of references to IFocusContainer instances, not just one.
  2. Code the VM defensively. You don't know whether there are 0, 1 or 20 views listening.
  3. The "target" parameter of SetFocus() should probably be "loosely" coupled to the VM. You don't want the VM caring about the exact control names in the UI. Rather, the VM should indicate a name that is defined solely for focus management. In my case, I created some attached properties that would allow me to "tag" controls with "focus names".

To implement the interface, you can:

  1. Implement it in the code-behind
  2. Create some behaviors that know how to attach to the ViewModel that is present in the DataContext.

There's nothing wrong with implementing it on the Code Behind, but the behavior approach does allow a XAML only hookup if that's important to you.

In the implementation of the interface, you can use the visual tree to locate the control, or you could just code up a switch statement for a known set of focusable items.

NathanAW
  • 3,329
  • 18
  • 19