WPF 4:PropertyChanged 不更新绑定

And*_*lon 5 c# wpf binding

在我的 ViewModel 中,我有一个带有子属性“B”的类“A”,它也是一个自定义类。这两个类都实现了 INotifyPropertyChanged 并且 B 的 PropertyChanged 事件被连接起来以触发 A 的 PropertyChanged 事件(具有正确的属性名称“B”)。

我的 ViewModel 上也有一个 DependencyProperty“DPB”,它通过一个非常简单的绑定(new Binding(“AB”))绑定到代码中的 B。

现在我的视图中有三个文本框:

  • 1 绑定到 ABC(B 的属性)
  • 1 直接绑定到 AB
  • 1 绑定到 DPB

第一次运行时,AB 和 DPB 文本框都显示正确的值。但是当我更改 ABC 文本框时,只有 AB 文本框会更新 - DPB 文本框不会更新。

我已经调试了所有的 PropertyChanged 通知代码,它们都被正确传递的值击中。

问题似乎是在触发 PropertyChanged 事件时没有更新 DependencyProperty(或其绑定)。谁能告诉我为什么或如何改变这种行为?

谢谢你。

Ale*_*hik 6

我有一个坏消息要告诉你。

DependencyObject.SetValue检查位于内部,它验证新值是否等于旧值。因此,如果您绑定到A.B并且更改为A.B.C产生 PropertyChanged 事件A.BBindingmechanizm 将处理此事件甚至调用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)