WPF-MVVM:从ViewModel设置UI控件焦点

在MVVM体系结构中设置控制焦点的一个好习惯是什么?

我设想的方式是在ViewModel上有一个属性,在需要时触发焦点更改。 而且,UI控件绑定/侦听该属性,以便如果更改,将设置适当的焦点。

我把它看作是一个ViewModel的东西,因为我想在ViewModel执行某个动作之后设置合适的焦点,比如加载某些数据。

最佳做法是什么?

使用IsFocused附加属性build议在这里的答案: 在视图模型(C#)中设置焦点在WPF中的文本框

然后,您可以简单地绑定到您的viewmodel属性。

如果您正在使用Caliburn.Micro,这是我创build的一个服务,用于将Focus设置为从Screeninheritance的视图中的任何Control。

注意:这只有在您为您的MVVM框架使用Caliburn.Micro时才有效。

public static class FocusManager { public static bool SetFocus(this IViewAware screen ,Expression<Func<object>> propertyExpression) { return SetFocus(screen ,propertyExpression.GetMemberInfo().Name); } public static bool SetFocus(this IViewAware screen ,string property) { Contract.Requires(property != null ,"Property cannot be null."); var view = screen.GetView() as UserControl; if ( view != null ) { var control = FindChild(view ,property); bool focus = control != null && control.Focus(); return focus; } return false; } private static FrameworkElement FindChild(UIElement parent ,string childName) { // Confirm parent and childName are valid. if ( parent == null || string.IsNullOrWhiteSpace(childName) ) return null; FrameworkElement foundChild = null; int childrenCount = VisualTreeHelper.GetChildrenCount(parent); for ( int i = 0; i < childrenCount; i++ ) { FrameworkElement child = VisualTreeHelper.GetChild(parent ,i) as FrameworkElement; if ( child != null ) { BindingExpression bindingExpression = GetBindingExpression(child); if ( child.Name == childName ) { foundChild = child; break; } if ( bindingExpression != null ) { if ( bindingExpression.ResolvedSourcePropertyName == childName ) { foundChild = child; break; } } foundChild = FindChild(child ,childName); if ( foundChild != null ) { if ( foundChild.Name == childName ) break; BindingExpression foundChildBindingExpression = GetBindingExpression(foundChild); if ( foundChildBindingExpression != null && foundChildBindingExpression.ResolvedSourcePropertyName == childName ) break; } } } return foundChild; } private static BindingExpression GetBindingExpression(FrameworkElement control) { if ( control == null ) return null; BindingExpression bindingExpression = null; var convention = ConventionManager.GetElementConvention(control.GetType()); if ( convention != null ) { var bindablePro = convention.GetBindableProperty(control); if ( bindablePro != null ) { bindingExpression = control.GetBindingExpression(bindablePro); } } return bindingExpression; } } 

如何使用这个?

从inheritance自Caliburn.Micro.Screen或Caliburn.Micro.ViewAware的ViewModel

this.SetFocus(()=>ViewModelProperty);this.SetFocus("Property");

怎么运行的?

此方法将尝试在视图树中search元素,并将焦点设置为任何匹配的控件。 如果没有find这样的控制,那么它将利用Caliburn.Micro使用的BindingConventions。

例如,

它将在控件的BindingExpression中寻找Propery。 对于TextBox,它会看看这个属性是否绑定到Text属性,然后焦点将被设置。

ViewModel将一个事件引发给View,告诉它该操作已经完成,View将设置焦点。

您可以为视图引入一个界面,以便ViewModel可以告诉视图来设置焦点。 WPF应用程序框架(WAF)的BookLibrary示例应用程序显示了如何执行此操作。 请看看BookListViewModel。

这个问题已经被问了几次了,不幸的是答案只适用于WPF。 所以对于使用MVVM的银光灯,你也可以绑定任何属性的细节,请访问以下链接

http://codenicely.blogspot.com/2012/01/how-to-set-textbox-focus-in-silverlight.html