如何使用MVVM将焦点设置到文本框?

时间:2011-07-18 18:54:00

标签: c# wpf xaml mvvm

如何从ViewModel wpf中聚焦文本框?

<TextBox Name="PropertySearch"
         Text="{Binding UpdateSourceTrigger=PropertyChanged, 
                        Mode=TwoWay, Path=PropertySearch, 
                        ValidatesOnDataErrors=True}"  
         Width="110" 
         Height="25" 
         Margin="10" />

4 个答案:

答案 0 :(得分:44)

您可以通过向ViewModel添加属性(或使用现有属性)来指示何时应该发生SetFocus,但View应负责实际设置焦点,因为这纯粹与View相关。

您可以使用DataTrigger执行此操作。

查看:

<Grid Name="LayoutRoot" DataContext="{StaticResource MyViewModelInstance}">
    <Grid.Style>
        <Style>
            <Style.Triggers>
                <DataTrigger Binding="{Binding UserShouldEditValueNow}" Value="True">
                    <Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=PropertySearch}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Grid.Style>
    <TextBox   Name="PropertySearch"   Text="{Binding UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, Path=PropertySearch, ValidatesOnDataErrors=True}" Width="110" Height="25" Margin="10" />
</Grid>

视图模型:

// When you think the view should set focus on a control
this.UserShouldEditValueNow = true;

通过使用布尔ViewModel属性“UserShouldEditValueNow”简化了上面的示例。您可以将这样的属性添加到ViewModel中,或者使用一些指示此状态的其他属性。

注意:那么为什么在MVVM中这样做呢?一个原因是,假设View作者决定用ComboBox替换TextBox,或者甚至更好,假设你的属性是一个整数值,同时有一个TextBox来查看/编辑数字一个Slider作为另一种编辑相同值的方法,两个控件都绑定到同一个属性...... ViewModel将如何知道要设置焦点的控件? (当它甚至不知道哪个控件或控件首先绑定到它时)这样,View可以通过更改DataTrigger Setter中的ElementName绑定目标来选择要关注的控件。

快乐的编码!

答案 1 :(得分:10)

你应该问自己的问题是“为什么我的ViewModel需要知道哪个控件有焦点?”

我认为焦点是一个只有视图的属性;它是一种交互属性,与概念状态无关。这类似于控件的背景颜色:为什么要在VM中表示它?如果您需要以自定义方式管理焦点,最好使用视图级对象来完成工作。

答案 2 :(得分:3)

在父控件中,添加以下属性:

FocusManager.FocusedElement="{Binding ElementName=PropertySearch}" 

答案 3 :(得分:1)

虽然纯粹主义者可能会主张将其从VM中删除,但有时可能会从VM中执行此操作。

我的方法是让视图实现一个接口,将该接口传递给ViewModel,然后让VM调用接口上的方法。

示例:

public interface IFocusContainer
{
   void SetFocus(string target);
}

要记住几件事:

  1. VM可能会提供多个视图实例,因此您的VM可能希望拥有对IFocusContainer实例的引用集合,而不仅仅是一个。
  2. 防御性地编码虚拟机。你不知道是否有0,1或20个观点在听。
  3. SetFocus()的“target”参数应该“松散地”耦合到VM。您不希望VM关注UI中的确切控件名称。相反,VM应指明仅为焦点管理定义的名称。在我的例子中,我创建了一些附加属性,允许我用“焦点名称”“标记”控件。
  4. 要实现界面,您可以:

    1. 在代码隐藏
    2. 中实现它
    3. 创建一些知道如何附加到DataContext中存在的ViewModel的行为。
    4. 在Code Behind上实现它没有任何问题,但是如果这对你很重要,那么行为方法只允许XAML连接。

      在界面的实现中,您可以使用可视化树来定位控件,或者您可以为一组已知的可聚焦项目编写switch语句。