MVVM聚焦于文本框。

12

我要如何在不指定TextBox名称的情况下设置焦点?目前我正在执行以下操作:

<Window FocusManager.FocusedElement="{Binding ElementName=Username}">
    <Grid>
        <TextBox Text="{Binding Username}" Name="Username" />            
    </Grid>
</Window>

有没有不需要为TextBox指定名称的方法来实现这一点。因为我相信在MVVM中,通常使用Name元素意味着设计不良?


我认为为元素命名本身并不是不好的设计,但仅仅为了在代码后台引用而给元素命名应该避免。我认为你上面的观点没有任何问题。 - lesscode
考虑是否要使用触发器来执行视图中的特殊操作(动画和其他状态更改)- 对于这些操作,名称至关重要。 - Gusdor
6个回答

28

我认为在MVVM中使用Name元素通常意味着设计不良?

不,不是这样的。

MVVM模式并不是要消除所有代码后台文件中的代码。它是关于分离关注点和增加可测试性的。与视图相关的代码,如焦点处理,应该保留在视图的代码后台文件中。但是,在视图的代码后台文件中看到应用程序逻辑或数据库连接管理将是不好的。

可以在WPF应用框架(WAF)项目中找到符合MVVM模式的代码后台文件中的MVVM示例。


11
MVVM模式并不是要消除代码后台文件中的所有代码。 - ktutnik

8
简单的方法是在UserControl_Load事件中设置焦点。
        this.txtBox.Focus();
        txtBox.Focusable = true;
        Keyboard.Focus(txtBox);

MVVM并不意味着您不能将代码放在代码后台文件中。 事实上,不要让任何模式限制您找到最佳编码方式。


在调用Focus()之后设置Focusable - Tim Sylvester

4

我在类似问题的答案中记录了一种“纯MVVM”方法来解决这个问题。该解决方案涉及使用附加属性和框架,从ViewModel向View传递接口命令。


http://geekswithblogs.net/HouseOfBilz/archive/2009/08/27/adventures-in-mvvm-ndash-binding-commands-to-any-event.aspx - Agies

3

0
实际上,我觉得布尔类型的附加属性解决方案有点不太干净和笨拙,因为你必须找到一个方法来确保你的视图模型属性的下一个设置确实会引发附加属性更改事件。
一个简单而更优雅的解决方案是,将你的行为绑定到属性类型上,你可以确定下一个值总是与之前不同,从而确保你的附加属性更改事件每次都会被引发。
最简单的类型是整数。因此,解决方案通常是以下组合:
该行为:
public static class TextBoxFocusBehavior
{
    public static int GetKeepFocus(DependencyObject obj)
    {
        return (int)obj.GetValue(KeepFocusProperty);
    }

    public static void SetKeepFocus(DependencyObject obj, int value)
    {
        obj.SetValue(KeepFocusProperty, value);
    }

    // Using a DependencyProperty as the backing store for KeepFocus.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty KeepFocusProperty =
        DependencyProperty.RegisterAttached("KeepFocus", typeof(int), typeof(TextBoxFocusBehavior), new UIPropertyMetadata(0, OnKeepFocusChanged));

    private static void OnKeepFocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        TextBox t = d as TextBox;
        if (t != null)
        {
            t.Focus();
        }
    }
}

视图模型属性:
    public int InputFocus
    {
        get { return _inputFocus; }
        private set
        {
            _inputFocus = value;
            Notify(Npcea.InputFocus);
        }
    }

使用附加行为的方法:

 <TextBox  v:TextBoxFocusBehavior.KeepFocus="{Binding InputFocus}"/>

最后在虚拟机中使用该属性:
    public void YouMethod()
    {
        //some code logic
        InputFocus++;//<= the textbox focus
    }

一些非常恶意的人可能会说这个逻辑受到 int32 大小限制的约束。嗯... 我现在选择忽略他们;-)


0
我认为在MVVM中使用Name元素通常意味着设计不良,对吗?
不是的。
根据微软MVP的说法,不仅在WPF中命名控件是一种不好的做法,而且会对性能造成相当大的影响。只是想传递一些智慧的话。
我同意Sean Du的观点,不要让任何模式完全限制你,我认为应该尽可能避免性能损失。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接