在我的ViewModel中,我有一个带有子属性“B”的类“A”,它也是一个自定义类。两个类都实现了INotifyPropertyChanged,并且B的PropertyChanged事件被连接起来触发A的PropertyChanged事件(具有正确的属性名称“B”)。
我的ViewModel上还有一个DependencyProperty“DPB”,它在代码中绑定到B,带有非常简单的绑定(new Binding(“A.B”))。
现在我的视图中有三个TextBox:
首次运行时,A.B和DPB文本框都显示正确的值。但是当我更改A.B.C文本框时,只更新A.B文本框 - 不更新DPB文本框。
我已经通过所有PropertyChanged通知代码进行了调试,并且它们都被传递了正确的值。
问题似乎是在触发PropertyChanged事件时未更新DependencyProperty(或它的绑定)。谁能告诉我为什么或如何改变这种行为?
谢谢。答案 0 :(得分:4)
我有个坏消息。
在DependencyObject.SetValue
内找到检查,验证新值是否等于旧值。因此,如果您绑定到A.B
,并且更改A.B.C
会为A.B
生成PropertyChanged事件,则Binding
机制会处理此事件,甚至会调用DependencyObject.SetValue
。但是(由于新旧A.B
值相等),不会对DP应用任何更改。
为了实现正确的DP激活,您应该创建A.B的新实例,这一点非常令人头疼。
<强>已更新强>
您可以使用Freezable对象,该对象支持在其属性更改时已更改的通知。 DependencyObject正确使用Freezables,因此下一个示例可以满足您的需求。
模型类:
public class A
{
public A()
{
this.B = new B();
}
public B B
{
get; private set;
}
}
public class B : Freezable, INotifyPropertyChanged
{
protected override Freezable CreateInstanceCore()
{
return new B();
}
private string _c = "initial string";
public string C
{
get
{
return _c;
}
set
{
this._c = value;
this.OnPropertyChanged("C");
this.OnChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
var safe = this.PropertyChanged;
if (safe != null)
{
safe(this, new PropertyChangedEventArgs(name));
}
}
}
Xaml:
<StackPanel>
<TextBox Text="{Binding A.B.C}" />
<TextBox Text="{Binding MyProperty.C}" />
<Button Click="Button_Click"/>
</StackPanel>
代码背后:
public partial class TextBoxesView : UserControl
{
public TextBoxesView()
{
InitializeComponent();
this.A = new A();
this.DataContext = this;
BindingOperations.SetBinding(this, TextBoxesView.MyPropertyProperty, new Binding("A.B"));
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.A.B.C = DateTime.Now.ToString();
}
public A A
{
get;
private set;
}
public B MyProperty
{
get
{
return (B)this.GetValue(TextBoxesView.MyPropertyProperty);
}
set
{
this.SetValue(TextBoxesView.MyPropertyProperty, value);
}
}
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty",
typeof(B),
typeof(TextBoxesView),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.None, (d, e) => { }));
}