【问题标题】:WPF 4 : PropertyChanged not updating BindingWPF 4:PropertyChanged 不更新绑定
【发布时间】:2011-07-29 22:54:47
【问题描述】:

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

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

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

  • 1 绑定到 A.B.C(B 的属性)
  • 1 直接绑定到 A.B
  • 1 绑定到 DPB

第一次运行时,A.B 和 DPB 文本框都显示正确的值。但是当我更改 A.B.C 文本框时,只有 A.B 文本框被更新 - DPB 文本框没有更新。

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

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

谢谢。

【问题讨论】:

  • 您可能需要在绑定中添加Mode=TwoWay。但是,我不确定我是否正确理解了您的问题,您可以添加一些代码吗?
  • 如果你稍微构建一下类结构并将其代码粘贴到这里会更好看...

标签: c# wpf binding


【解决方案1】:

我有个坏消息要告诉你。

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

【讨论】:

  • 嗯,我害怕那个。您知道如何执行相等性检查吗?如果我重写 equals 和 gethash 方法,它会更新吗?
  • Equals/GetHash 方法无济于事,因为对象保持不变。其实我不知道你的目的,也不能给你建议。如果我是你,我会认为这样的麻烦是因为设计不好。您也可以尝试使用 Freezable。我在答案中添加了一些解释代码。
  • 感谢您的帮助,尤其是 Freezable 的建议,我现在正在调查。我同意这在某种程度上是一个设计问题,但是在设计时不知道 B 类类型的情况下使用它,因此需要中间属性。感谢您的帮助,并会尽快将其标记为已回答。
  • 在查看 Freezable 之后,我可以看到它是如何使用的,但只是开销很大。但是您的回答是正确的,因为不能强制 DP 更新 PropertyChanged 通知。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-05-22
  • 1970-01-01
  • 2013-08-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-15
相关资源
最近更新 更多