在MVVM架构中设置控制焦点的良好做法是什么。
我设想它的方式是使用ViewModel上的属性,它会在需要时触发焦点更改。并且让UI控件绑定/侦听该属性,以便在它更改时,将设置适当的焦点。
我将其视为ViewModel,因为我希望在ViewModel执行某个操作后设置适当的焦点,例如加载某些数据。
最佳做法是什么?
答案 0 :(得分:28)
使用此处答案中建议的IsFocused附加属性:Set focus on textbox in WPF from view model (C#)
然后,您只需绑定到viewmodel中的属性即可。
答案 1 :(得分:13)
如果您使用的是Caliburn.Micro,我创建的服务是将Focus设置为从Screen继承的视图中的任何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;
}
}
如何使用?
从您继承自Caliburn.Micro.Screen或Caliburn.Micro.ViewAware的ViewModel
this.SetFocus(()=>ViewModelProperty);
要么
this.SetFocus("Property");
它如何运作?
此方法将尝试在Visual Tree of View中搜索元素,焦点将设置为任何匹配的控件。如果没有找到这样的控件,那么它将使用Caliburn.Micro使用的BindingConventions。
例如,
它将在控件的BindingExpression中查找Propery。 对于TextBox,它将查看此属性是否绑定到Text属性,然后将设置焦点。
答案 2 :(得分:1)
ViewModel向View抛出一个事件,告诉它该动作已经完成,View将设置焦点。
答案 3 :(得分:0)
您可以为View引入一个界面,以便ViewModel可以告诉View设置Focus。 WPF Application Framework (WAF) 的BookLibrary示例应用程序显示了如何执行此操作。请查看BookListViewModel。
答案 4 :(得分:0)
这个问题已被问过几次,不幸的是答案只适用于WPF。因此对于使用MVVM的银灯,您还可以绑定任何属性以获取详细信息,请访问以下链接
http://codenicely.blogspot.com/2012/01/how-to-set-textbox-focus-in-silverlight.html