PropertyChanged事件多次触发

时间:2014-05-28 11:31:15

标签: c# wpf events event-handling

我有一个有几个属性的类。当这些被更改时,PropertyChangedEvent被提升。某些属性依赖于其他属性,因此当其中一个依赖项发生更改时,它会为自身以及依赖于它的属性引发PropertyChangedEvent

我的问题是,我已将PropertyChangedEventHandler附加到此类的实例。当其中一个属性依赖于另一个属性时,将多次调用此事件处理程序。有办法解决这个问题吗?

更新

一些小代码,只是为了说明我在谈论的内容:

    private bool _foo;
    private bool _bar;

    public bool Foo
    {
        get { return _foo; }
        set
        {
            _foo = value;
            OnPropertyChanged("Foo");
            OnPropertyChanged("Baz");
        }
    }

    public bool Bar
    {
        get { return _bar; }
        set
        {
            _bar = value;
            OnPropertyChanged("Bar");
            OnPropertyChanged("Baz");
        }
    }

    public bool Baz
    {
        get
        {
            return Foo && Bar;
        }
    }

设置Foo后,Baz也会发生变化。如果我附加PropertyChangedEventHandler,则在设置Foo时会调用两次。我只想打电话一次。周围有一个很好的方法吗?

2 个答案:

答案 0 :(得分:4)

您需要做的就是从逻辑上思考这个问题片刻以获得答案。您有以下情况:

public bool Foo
{
    get { return _foo; }
    set
    {
        _foo = value;
        OnPropertyChanged("Foo");
        OnPropertyChanged("Baz");
    }
}

public bool Bar
{
    get { return _bar; }
    set
    {
        _bar = value;
        OnPropertyChanged("Bar");
        OnPropertyChanged("Baz");
    }
}

public bool Baz
{
    get
    {
        return Foo && Bar;
    }
}

我的第一个评论是,如果 一次多次提升INotifyPropertyChanged.PropertyChanged事件,那么你最好使用这样的实现,使您能够立即为任意数量的属性引发事件:

protected virtual void NotifyPropertyChanged(params string[] propertyNames)
{
    if (PropertyChanged != null)
    {
        foreach (string propertyName in propertyNames) 
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

...

NotifyPropertyChanged("Foo", "Bar");

回到你的问题......让我们考虑你的要求:

  1. Baz的值发生变化时,您需要通知界面。
  2. FooBar属性值发生更改时,可以更改其值...因此,您需要在其中任何一个更改时通知接口,如您所知。

    现在,@ Franck评论说你应该从属性1的setter触发一个更新属性2的方法,通过更改将触发他自己的属性更改。让我们考虑一下......大概,您需要从FooBar属性设置器中调用相同的方法才能使其正常工作。

    然而,实际发生的是,当FooBar值发生更改时,该方法将被调用两次,因此INotifyPropertyChanged通知仍会被调用两次,虽然现在来自Baz制定者......但很明显,这并没有改善。

    然而,还有一个选项对您有用。为此,您需要添加一个帮助方法来更新FooBar属性值代表INotifyPropertyChanged接口通知Baz public void UpdateBaz(bool? foo, bool? bar) { if (foo != null) Foo = foo; if (bar != null) Bar = bar; OnPropertyChanged("Baz"); } 属性:

    OnPropertyChanged("Baz")

    当然,为了实现这一目标,您需要从两个属性处理程序中删除对public bool Foo { get { return _foo; } set { _foo = value; OnPropertyChanged("Foo"); } } public bool Bar { get { return _bar; } set { _bar = value; OnPropertyChanged("Bar"); } } 的调用:

    Foo

    但是,如果您想通过Bar更新BindingBaz属性,那么您将回到@Franck关于调用此方法两次和两个属性的建议单独更新。在这种情况下,似乎你只需要忍受两次通知的{{1}}财产。

答案 1 :(得分:0)

在您的setter中插入一个值已更改的检查,如:

set
{
   if(value != [yourfield])
   {
      yourfield = value;
      OnPropertyChanged(Yourfield);
   }
}