加载WPF MVVM焦点字段
我有一个视图,它下面有一个单独的TextBox
和一对Button
。 当窗口加载时,我希望TextBox
有焦点。
如果我不使用MVVM,我只需要在Loaded事件中调用TextBox.Focus()
。 然而,我的ViewModel不知道我的看法,所以我怎么能做到这一点,而不是把代码放到我的视图的代码隐藏?
编辑:在阅读答案后,我决定把这个代码在视图xaml
<DockPanel FocusManager.FocusedElement="{Binding ElementName=MessageTextBox}"> <TextBox Name="MessageTextBox" Text="{Binding Message}"/> </DockPanel>
如果这不是初始页面焦点,我可能会推荐Jon Galloway的答案,因为它可以从ViewModel控制。
如果它让你感觉更好(这让我感觉更好),你可以使用附加属性在Xaml中做到这一点:
http://msdn.microsoft.com/en-us/library/system.windows.input.focusmanager.focusedelement.aspx
如果你知道这些技巧,你可以在代码隐藏中做任何事情。 幸运的是,你不必执行这个技巧 – MS为你做了。
在这种情况下,我认为可以将代码放入视图中。 将焦点设置为控件会影响用户界面的行为而不是应用程序的逻辑,因此是视图的责任。
- 在你的ViewModel中有一个属性,指明哪个是当前焦点的元素。
-
使用FocusManager绑定到该属性。
<Window FocusManager.FocusedElement="{Binding ElementName=ViewModel.FocusedItem}"/>
你的ViewModel是一个翻译器,它只是为View提供信息,所以你可以添加任何信息到View需要的VM上。
其实,是不是重点关注UI? MVVM是关于分离关注的 – 模型中属于模型,属于视图的是在视图中,而模型和视图一起绑定在ViewModel中(这当然是过于简单的描述)。
这意味着UI逻辑保留在View中 – 在我看来,TextBox.Focus()是适当的方式来实现这一点。
我认为重点控制是非常“可视的”,所以不会有任何问题,在后面的代码。
虚拟机的想法是将逻辑从View中移走,并为要绑定的视图提供数据绑定友好的模型版本。 这并不一定意味着所有的代码都应该存在于虚拟机中,只要是逻辑代码以及任何不直接绑定到UI的东西。
在“WPF初始焦点梦魇”之后,根据堆栈上的一些答案,以下certificate对我来说是最好的解决scheme。
首先,添加你的App.xaml的OnStartup()如下:
EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent, new RoutedEventHandler(WindowLoaded));
然后在App.xaml中添加“WindowLoaded”事件:
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)); })); }
线程问题必须使用,因为WPF的初始焦点大多因为一些框架竞争条件而失败。
我发现以下解决scheme是最好的,因为它是全球使用整个应用程序。
希望能帮助到你…
奥兰