双向绑定view's DependencyProperty到viewmodel's属性
本文关键字:viewmodel 属性 DependencyProperty 绑定 view | 更新日期: 2023-09-27 18:01:36
网络上的多个来源告诉我们,在MVVM
中,视图和视图模型之间的通信/同步应该通过依赖属性发生。如果我理解正确的话,视图的依赖属性应该使用双向绑定绑定到视图模型的属性上。现在,以前也有人问过类似的问题,但没有足够的答案。
在我开始分析这个相当复杂的问题之前,我有一个问题:
我如何同步一个自定义视图的DependencyProperty
与视图模型的属性?
在理想情况下,您可以简单地将其绑定为:
<UserControl x:Class="MyModule.MyView" MyProperty="{Binding MyProperty}">
这不起作用,因为MyProperty
不是UserControl
的成员。哎!我试过不同的方法,但都不成功。
一个解决方案是定义一个基类UserControlEx
,它具有必要的依赖属性以使上述工作正常进行。然而,这很快就会变得非常混乱。不够好!
如果你想在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>
在您的情况下,MyViewProperty
和MyViewModelProperty
都将被命名为MyProperty
,但我使用了不同的名称,只是为了清楚地了解什么是什么。
我用的是Caliburn。Micro用于从视图中分离ViewModel。不过,它可能在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);
}
VM // in the class of the ViewModel: MyViewModel
public string ViewModelStringProperty { get; set; }
注意,这种实现完全缺乏INotifyPropertyChanged
接口的实现。您需要正确地更新此代码。
让我们说你已经在视图中定义了你的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>