WPF MVVM Focus Field on Load

2019-01-21 10:36发布

I have a View that has a single TextBox and a couple Buttons below it. When the window loads I want that TextBox to have focus.

If I was not using MVVM I would just call TextBox.Focus() in the Loaded event. However my ViewModel does not know about my view so how can I accomplish this without putting code into the codebehind of my view?

EDIT: After reading the answers I decided to put this code in the view xaml

<DockPanel FocusManager.FocusedElement="{Binding ElementName=MessageTextBox}">    
    <TextBox Name="MessageTextBox" Text="{Binding Message}"/>
</DockPanel>

If this were anything other than initial page focus I would probably recommend Jon Galloway's answer since it can be controlled from the ViewModel.

6条回答
我命由我不由天
2楼-- · 2019-01-21 10:53

In this case I think that it is fine to put the code into the view. Setting focus to a control affects the behaviour of the user interface rather than logic of the application and therefore is the responsibility of the view.

查看更多
萌系小妹纸
3楼-- · 2019-01-21 10:59

I'd consider the control with focus to be very much "visual only", so wouldn't have any problem with that being in code behind.

The idea of a VM is to move logic away from the View, and provide a databinding friendly version of your model for the view to bind to. This doesn't necessarily mean that all code should live in the VM, just the logic code and anything that isn't directly tied to the UI.

查看更多
神经病院院长
4楼-- · 2019-01-21 11:00

Actually, isn't focus a UI concern? MVVM is about separating concerns - what belongs to model is in model, what belongs to view is in view, and what bind model and view together is in ViewModel (this is of course oversimplified description).

This means, that UI logic remains in View - TextBox.Focus() is, in my opinion, appropriate way to make this happen.

查看更多
啃猪蹄的小仙女
5楼-- · 2019-01-21 11:01

After having a 'WPF Initial Focus Nightmare' and based on some answers on stack, the following proved for me to be the best solution.

First, add your App.xaml OnStartup() the followings:

EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent,
          new RoutedEventHandler(WindowLoaded));

Then add the 'WindowLoaded' event also in App.xaml :

void WindowLoaded(object sender, RoutedEventArgs e)
    {
        var window = e.Source as Window;
        System.Threading.Thread.Sleep(100);
        window.Dispatcher.Invoke(
        new Action(() =>
        {
            window.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));

        }));
    }

The threading issue must be use as WPF initial focus mostly fails due to some framework race conditions.

I found the following solution best as it is used globally for the whole app.

Hope it helps...

Oran

查看更多
三岁会撩人
6楼-- · 2019-01-21 11:12

If it makes you feel better (it makes me feel better) you can do this in Xaml using an attached property:

http://msdn.microsoft.com/en-us/library/system.windows.input.focusmanager.focusedelement.aspx

Anything you can do in codebehind you can do in Xaml if you know the tricks. Fortunately, you didn't have to implement this trick - MS did it for you.

查看更多
贪生不怕死
7楼-- · 2019-01-21 11:13
  1. Have a property in your ViewModel which indicates which is the currently focused element.
  2. Use the FocusManager to bind to that property.

    <Window FocusManager.FocusedElement="{Binding ElementName=ViewModel.FocusedItem}"/>
    

Your ViewModel is a translator which exists solely to provide information to the View, so you can add whatever information to the VM that the View needs to function.

查看更多
登录 后发表回答