代码之家  ›  专栏  ›  技术社区  ›  devdigital

从WPF中的视图设置ViewModel的属性

  •  2
  • devdigital  · 技术社区  · 14 年前

    I have a dependency property on my ViewModel which is the DataContext for my View. ViewModel没有对该视图的引用。ViewModel上的属性将引用视图上的控件,但我需要能够在XAML中设置此属性。

    How is this possible? 我有一个想法是开发一个自定义控件,它有一个属性属性和一个值属性,因此您可以在视图中执行类似的操作来设置ViewModel的属性:

    <PropertySetter Property="{Binding MyViewModelDependencyProperty}" Value="{Binding ElementName=aControlOnMyView" />
    

    在我走这条路之前,我想看看是否还有其他的方法可以采用?


    谢谢你详细的回复雷,但是如果我给你更多关于我要解决的问题的细节,你可能会更好地理解我为什么提到我所做的方法。

    基本上,我要做的就是当用户点击一个按钮时,将焦点设置为一个文本框。我已经编写了一个附加属性,您可以附加到按钮控件,指定触发器事件是什么(在本例中是“单击”事件),然后指定要关注的控件。这真的很好用,并且把所有东西都保存在XAML中。

    但是,我现在有了一个用例,在这个用例中,焦点应该从工具栏的一个按钮上的Click事件设置为一个任意的文本框。这个工具栏本身就是一个用户控件,它位于另一个用户控件内,而另一个用户控件内!此工具栏需要在不同的表单中重用,每次单击按钮后要设置焦点的控件在每个表单中都不同。

    这就是为什么我想让焦点控件(即文本框)成为视图模型本身的一个属性(在我的viewModel基础上更精确),并拥有viewModel基础代码(工具栏绑定到的代码),在单击按钮时将焦点设置为控件(例如,在viewModel基础上调用add/edit方法)。

    在UnitTestLand中,要关注属性的控件将为空,因此不会调用它的.focus()方法。所以我看不出有什么问题。我的问题是如何从XAML设置Focus Control属性,这就是为什么我有PropertySetter的想法。

    我不喜欢ViewModel引用了视图上的控件,但我看不到实现我需要的其他方法。如果指示是否将焦点设置到控件的逻辑相当复杂,该怎么办?这肯定会出现在视图模型中吗?因此,拥有此uielement属性的ViewModel是否有任何危害?它仍然不知道它绑定到的特定视图,它只知道在ViewModel上发生某些操作时需要将焦点设置为某个控件。

    2 回复  |  直到 14 年前
        1
  •  7
  •   Ray Burns    14 年前

    我的第一反应(这是一个强烈的反应)是说“不要这样做!”通过向视图模型提供对用户界面一部分的引用,您将破坏使视图模型如此强大和有用的封装。

    例如,如果要对视图模型进行单元测试或将其序列化到磁盘上,该怎么办?在每种情况下,您的UI都将不存在,因为根本没有视图。您的测试将错过覆盖范围,您的重建将不完整。

    如果视图模型实际上需要对UI对象的引用,并且没有更好的方法来构建它,那么最好的解决方案是让视图模型本身构造那些它需要引用的控件。然后,您的视图可以通过绑定将该控件合并为ContentPresenter的内容,并提供配置该控件的样式,包括用于提供其内容的ControlTemplate。因此:

    public class MyViewModel
    {
      public ListBox SpecialControl { get; set; }
      public MyViewModel()
      {
        SpecialControl = new ListBox();
      }
    }
    

    <DataTemplate TargetType="{x:Type local:MyViewModel}">
      <DataTemplate.Resources>
        <Style TargetType="ListBox" ... />
      </DataTemplate.Resources>
      ...
      <ContentPresenter Content="{Binding SpecialControl}" />
    </DataTemplate>
    

    其他可能性包括:

    1. 让视图模型实际上从控件类派生,然后重写onApplyTemplate(),并使用getTemplateChild查找名称以“part_u”开头的模板项。
    2. 实现采用属性名称的附加属性,在DataContext中查找该属性,并将其设置为该属性附加到的DependencyObject。
    3. 实现属性设置器的想法

    我的选择2如下:

    <DataTemplate TargetType="{x:Type MyViewModel}">
      ...
      <TextBox local:PropertyHelper.SetViewModelToThis="SpecialControl" />
      ...
    </DataTemplate>
    

    setViewModelToThisPropertyChangedCallback中的代码将从DataContext获取视图模型,对其进行反射以查找“SpecialControl”属性,然后将其设置为文本框。请注意,setViewModelToThis的实现必须考虑到可能没有立即设置DataContext,并且可能需要删除旧设置并创建新设置才能对其进行更改。

        2
  •  2
  •   decyclone    14 年前

    首先, DataContext 控制的对象应该是 ViewModel object and not a property of it. 第二,当你 TwoWay 绑定的属性 视图模型 对于控件,控件值的更改将更新(在您的情况下,“set”)的值 视图模型 的财产