如何使用MVVM对文本框设置焦点

本文关键字:设置 焦点 文本 何使用 MVVM | 更新日期: 2023-09-27 18:02:21

如何从ViewModel wpf聚焦文本框?

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

如何使用MVVM对文本框设置焦点

你可以通过添加一个属性到你的ViewModel(或使用一个现有的属性),这表明SetFocus应该发生,但视图应该负责实际设置焦点,因为这纯粹是视图相关的。

你可以用一个datattrigger来做这个。

视图:

<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>

ViewModel:

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

上面的例子通过使用一个布尔ViewModel属性"UserShouldEditValueNow"来简化。你可以像这样添加一个属性到你的ViewModel,或者使用其他一些现有的属性来指示这个状态。

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

编码快乐!

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

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

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

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

虽然纯粹主义者可能会争论将此从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应该指示一个仅为焦点管理而定义的名称。在我的例子中,我创建了一些附加属性,允许我用"焦点名称"标记"控件。

要实现接口,您可以:

  1. 在后台代码
  2. 中实现
  3. 创建一些知道如何附加到DataContext中存在的ViewModel的行为

在后台代码上实现它没有什么错,但是如果对您很重要的话,行为方法确实允许仅XAML连接。

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