我正在尝试使用c#和XAML遵循MVVM设计范例。我在使用嵌套用户控件时遇到了麻烦。我试图将嵌套用户控件上的元素绑定到ViewModel中的一个值(通过DataContext属性绑定到视图)。相同的ViewModel用于外部和嵌套的用户控件。
它部分按原样工作,但是从ViewModel到嵌套的用户控件的更改只是单向的。我需要在嵌套用户控件中所做的更改传播回ViewModel。
从主视图的XAML开始,我有:<UserControl>
<!-- ... -->
<UserControl.DataContext>
<local:MyViewModel x:Name="myViewModel" />
</UserControl.DataContext>
<!-- ... -->
<local:NestedUserControl
x:Name="nestedUserControl"
CustomNestedValue="{Binding Path=CustomValue, ElementName=myViewModel, Mode=TwoWay}" />
</UserControl>
在ViewModel的c#代码中:
// Constructor
public MyViewModel()
{
CustomValue = true;
}
private bool _customValue;
public bool CustomValue
{
get { return _customValue; }
set
{
if (_customValue != value)
{
_customValue = value;
RaisePropertyChanged ("CustomValue");
}
}
}
在NestedUserControl
后面的代码中,我有:
public static readonly DependencyProperty CustomNestedValueProperty =
DependencyProperty.Register (
"CustomNestedValue",
typeof (bool),
typeof (NestedUserControl),
new FrameworkPropertyMetatdata
{
BindsTwoWayByDefault = true,
PropertyChangedCallback =
new PropertyChangedCallback (CustomNestedValueChangedCallback)
});
public bool CustomNestedValue
{
get { return (bool) GetValue (CustomNestedValueProperty); }
set { SetValue (CustomNestedValueProperty, value); }
}
protected static void CustomNestedValueChangedCallback (
DependencyObject Source,
DependencyPropertyChangedEventArgs e)
{
bool value = (bool) e.NewValue;
NestedUserControl control = source as NestedUserControl;
control.OnCustomValueChange (value);
}
public void OnCustomValueChange (bool value)
{
RaisePropertyChanged ("CustomNestedValue");
// Do other stuff ...
}
// This function is where the nested user control gets direct
// interactions from the user which cause the dependency
// property to change. When this event occurs, the change needs
// to be communicated back up to the view model.
private void _onPreviewMouseDown (object sender, MouseButtonEventArgs e)
{
CustomNestedValue = !CustomNestedValue;
}
[注意:在XAML中设置绑定时,我不仅将绑定模式设置为two - way,而且还尝试将此设置为上述代码中DependencyProperty的默认行为。没有运气。)
嵌套用户控件的代码和ViewModel代码都包含下面的PropertyChangedEventHandler
事件/响应,这是INotifyPropertyChanged
接口所必需的。据我所知,这就是XAML元素和ViewModel之间的绑定保持同步的方式。
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
try
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
catch (Exception e)
{
// ...
}
}
当我运行代码时,每当为NestedUserControl
调用RaisePropertyChanged
函数时,PropertyChanged
事件总是null。这只是嵌套用户控件的问题,而不是外部的问题。这个事件不应该通过绑定机制自动设置吗?
我已经为此挣扎了好几天了,但无济于事。任何帮助都将非常感激。谢谢!
绑定到DependencyObject
的操作不使用INotifyPropertyChanged
接口。事实上,如果您在NestedUserControl
的CustomNestedValue
属性的getter或setter中设置了一个断点,您会发现在XAML中绑定时它永远不会命中。从本质上讲,INotifyPropertyChanged
是一种无需从DependencyObject
派生而实现绑定的方法。
当MyViewModel.CustomValue
绑定到NestedUserControl
时,绑定代码调用(伪代码):
NestedUserControl.SetBinding(binding, NestedUserControl.CustomNestedValueProperty)
INotifyPropertyChanged.PropertyChanged
事件永远不会被注册,并且将保持为空。然而,这并不一定能回答为什么值不返回到ViewModel。
无论如何,您可以删除一些移动部分并使用
public static readonly DependencyProperty CustomNestedValueProperty =
DependencyProperty.Register("CustomNestedValue",
typeof (bool),
typeof (NestedUserControl),
null);
public bool CustomNestedValue
{
get { return (bool) GetValue (CustomNestedValueProperty); }
set { SetValue (CustomNestedValueProperty, value); }
}
这就是我的大多数DependencyProperties是如何编写的,他们确实支持TwoWay
绑定