在我的 ViewModel 中,我有一个带有子属性“B”的类“A”,它也是一个自定义类。这两个类都实现了 INotifyPropertyChanged 并且 B 的 PropertyChanged 事件被连接起来以触发 A 的 PropertyChanged 事件(具有正确的属性名称“B”)。
我的 ViewModel 上也有一个 DependencyProperty“DPB”,它通过一个非常简单的绑定(new Binding(“AB”))绑定到代码中的 B。
现在我的视图中有三个文本框:
第一次运行时,AB 和 DPB 文本框都显示正确的值。但是当我更改 ABC 文本框时,只有 AB 文本框会更新 - DPB 文本框不会更新。
我已经调试了所有的 PropertyChanged 通知代码,它们都被正确传递的值击中。
问题似乎是在触发 PropertyChanged 事件时没有更新 DependencyProperty(或其绑定)。谁能告诉我为什么或如何改变这种行为?
谢谢你。
我有一个坏消息要告诉你。
DependencyObject.SetValue检查位于内部,它验证新值是否等于旧值。因此,如果您绑定到A.B并且更改为A.B.C产生 PropertyChanged 事件A.B,Bindingmechanizm 将处理此事件甚至调用DependencyObject.SetValue. 但是随后(由于旧A.B值和新值相等)不会对 DP 应用任何更改。
为了实现正确的 DP 触发,您应该创建 AB 的新实例,这会以令人头疼的方式结束。
更新
您可以使用 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));
}
}
}
Run Code Online (Sandbox Code Playgroud)
Xml:
<StackPanel>
<TextBox Text="{Binding A.B.C}" />
<TextBox Text="{Binding MyProperty.C}" />
<Button Click="Button_Click"/>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)
后面的代码:
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) => { }));
}
Run Code Online (Sandbox Code Playgroud)