WPF 4:PropertyChanged没有更新Binding

时间:2011-04-05 12:50:51

标签: c# wpf binding

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

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

现在我的视图中有三个TextBox:

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

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

我已经通过所有PropertyChanged通知代码进行了调试,并且它们都被传递了正确的值。

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

谢谢。

1 个答案:

答案 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) => {  }));
}