2009-07-24 60 views
45

我有一个视图,它有一个单独的TextBox和一对Button s。当窗口加载时,我希望TextBox有重点。WPF MVVM加载焦点域

如果我不使用MVVM,我会在Loaded事件中调用TextBox.Focus()。然而,我的ViewModel不知道我的视图,所以如何在不将代码放入视图的代码隐藏的情况下完成此任务?

编辑: 阅读的答案后,我决定把这个代码视图中的XAML

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

如果这不是初始页面的焦点其他我可能会建议乔恩·加洛韦的答案,因为它可以从控制什么ViewModel。

回答

14

在这种情况下,我认为可以将代码放入视图中。将焦点设置为控件会影响用户界面的行为而不是应用程序的逻辑,因此是视图的责任。

+1

这是什么样的我想。每次考虑将代码添加到视图时,我都觉得有点肮脏。在这种情况下,它似乎是有道理的。 – 2009-07-24 15:41:14

+14

我想,一旦我改变了我的MVVM理念从“无代码背后”到“最小和相关的代码背后的”我的生活变得轻松了许多。我没有听说安德森艾姆斯已经提到的附加属性,这听起来像一个很好的解决了低级趣味的代码背后给你,但不要害怕把*合法*,非逻辑的代码在UI。 – 2009-07-24 15:45:10

+4

我很同意你的意见。我认为从视图中消除代码是有道理的。重要的是视图中的代码应该与UI相关。虚拟机中的代码包含与模型相关的状态和其他逻辑。石蕊测试是代码是否可以/应该被测试。视图中的代码不能被测试。 – 2010-10-08 14:44:10

4

我认为焦点控制非常“只有视觉”,所以在代码背后没有任何问题。

虚拟机的想法是将逻辑从视图中移开,并为要绑定的视图提供数据绑定友好版本的模型。这并不一定意味着所有的代码都应该存在于虚拟机中,只是逻辑代码和任何不直接绑定到UI的东西。

8

其实,是不是焦点关注UI? MVVM是关于分离问题的 - 模型属于模型,属于视图的属于视图,并且模型和视图一起绑定在ViewModel中(这当然是过于简单的描述)。

这意味着,UI逻辑保留在视图中 - 在我看来,TextBox.Focus()是适当的方式来实现这一点。

10
  1. 在您的ViewModel中有一个属性,它指示哪个是当前焦点元素。
  2. 使用FocusManager绑定到该属性。

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

您的视图模型是存在只是为了给View提供的信息,这样你就可以添加任何信息到虚拟机的浏览需要的功能翻译。

2

经过“WPF初始聚焦梦魇”并基于堆栈上的一些答案,以下证明对我来说是最好的解决方案。

首先,添加您的应用程序。XAML OnStartup()以下内容:

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

然后还加了“WindowLoaded”事件中的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)); 

     })); 
    } 

线程问题必须用作WPF最初的重点主要是由于某种框架竞赛条件。

我发现下面的最佳解决方案,因为它是全球范围内用于整个应用程序。

希望它可以帮助...

奥兰