24

网络上的多个消息来源告诉我们,MVVM视图和视图模型之间的通信/同步应该通过依赖属性发生。如果我理解正确,视图的依赖属性应该使用双向绑定绑定到视图模型的属性。现在,以前也有人问过类似的问题,但没有足够的答案。

在我开始分析这个相当复杂的问题之前,这是我的问题:

如何将自定义视图DependencyProperty与视图模型的属性同步?

在理想的世界中,您只需将其绑定为:

<UserControl x:Class="MyModule.MyView" MyProperty="{Binding MyProperty}">

这不起作用,因为MyProperty不是UserControl. 嗬!我尝试了不同的方法,但没有一个被证明是成功的。

一种解决方案是定义一个基类,UserControlEx具有必要的依赖属性以使上述工作正常。然而,这很快变得非常混乱。还不够好!

4

3 回答 3

16

如果您想在 XAML 中执行此操作,您可以尝试使用样式来实现。

这是一个例子:

<UserControl x:Class="MyModule.MyView"
             xmlns:local="clr-namespace:MyModule">
    <UserControl.Resources>
        <Style TargetType="local:MyView">
            <Setter Property="MyViewProperty" Value="{Binding MyViewModelProperty, Mode=TwoWay}"/>
        </Style>
    </UserControl.Resources>
    <!-- content -->
</UserControl>

在您的情况下,两者都MyViewPropertyMyViewModelProperty被命名MyProperty,但我使用不同的名称只是为了清楚什么是什么。

于 2014-02-18T10:37:39.770 回答
7

我使用 Caliburn.Micro 将 ViewModel 与 View 分开。尽管如此,它可能在 MVVM 中以相同的方式工作。我猜 MVVM 也将视图的DataContext属性设置为 ViewModel 的实例。

看法

// in the class of the view: MyView
public string ViewModelString // the property which stays in sync with VM's property
{
    get { return (string)GetValue(ViewModelStringProperty); }
    set
    {
        var oldValue = (string) GetValue(ViewModelStringProperty);
        if (oldValue != value) SetValue(ViewModelStringProperty, value);
    }
}

public static readonly DependencyProperty ViewModelStringProperty =
    DependencyProperty.Register(
        "ViewModelString",
        typeof(string),
        typeof(MyView),
        new PropertyMetadata(OnStringValueChanged)
        );

private static void OnStringValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
    // do some custom stuff, if needed
    // if not, just pass null instead of a delegate
}    

public MyView()
{
    InitializeComponent();
    // This is the binding, which binds the property of the VM
    // to your dep. property.
    // My convention is give my property wrapper in the view the same
    // name as the property in the VM has.
    var nameOfPropertyInVm = "ViewModelString"
    var binding = new Binding(nameOfPropertyInVm) { Mode = BindingMode.TwoWay };
    this.SetBinding(SearchStringProperty, binding);
}

虚拟机

// in the class of the ViewModel: MyViewModel
public string ViewModelStringProperty { get; set; }

请注意,这种实现完全缺乏INotifyPropertyChanged接口的实现。您需要正确更新此代码。

于 2013-02-28T11:03:22.523 回答
4

假设您已经在 View 中定义了 DependencyProperty“DepProp”,并希望在 ViewModel 中使用完全相同的值(它实现了 INotifyPropertyChanged 但不实现 DependencyObject)。您应该能够在 XAML 中执行以下操作:

<UserControl x:Class="MyModule.MyView"
         xmlns:local="clr-namespace:MyModule"
             x:Name="Parent">
    <Grid>
        <Grid.DataContext>
            <local:MyViewModel DepProp="{Binding ElementName=Parent, Path=DepProp}"/>
        </Grid.DataContext>
    ...
    </Grid>
</UserControl>
于 2016-05-12T06:53:08.547 回答