torbonde
torbonde

Reputation: 2459

PropertyChangedEvent firing multiple times

I have a class with several properties. When these are changed, a PropertyChangedEvent raised. Some properties depend on other properties, so when one of the dependencies is changed, it raises a PropertyChangedEvent for itself, and for the property that depends on it.

My problem is, that I have attached a PropertyChangedEventHandler to an instance of this class. When one of the properties that is depended upon by another property, this event handler is called several times. Is there a way to get around this?

UPDATE

A little code, just to illustrate what I'm talking about:

    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;
        }
    }

When Foo is set, Baz changes as well. If I attach a PropertyChangedEventHandler, this will be called twice, when I set Foo. I only want to call it once. Is there a nice way around it?

Upvotes: 1

Views: 3907

Answers (2)

Sheridan
Sheridan

Reputation: 69959

All you need to do is think logically about this issue for a moment to get your answer. You have the following situation:

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;
    }
}

My first comment is that if you are going to raise your INotifyPropertyChanged.PropertyChanged event more than once at a time, then you'd be better off using an implementation like this, which would enable you to raise the event for as many properties as you like at once:

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

...

NotifyPropertyChanged("Foo", "Bar");

So back to your problem... let's think about your requirement:

  1. You need to notify the interface when the value of Baz changes.

Its value can be changed when either the Foo or Bar property values change... therefore you'll need to notify the interface when either of them changes, as you have.

Now, @Franck commented to say that You should from the setter of Property 1 trigger a method to update Property 2 which by changing will trigger his own property change. Let's think about that for a minute... presumably, you'd need to call this same method from both of the Foo or Bar property setters to make it work.

However, what would actually happen is that the when the Foo and Bar values are changed, the method would be called twice and so the INotifyPropertyChanged notification will still be called twice, albeit now coming from the Baz setter... so clearly, this is no improvement.

There is however, one more option that could work for you. For this to work, you'd need to add a helper method that would update the Foo or Bar property values and notify the INotifyPropertyChanged interface on behalf of the Baz property:

public void UpdateBaz(bool? foo, bool? bar)
{
    if (foo != null) Foo = foo;
    if (bar != null) Bar = bar;
    OnPropertyChanged("Baz");
}

Of course, for this to work, you'd need to remove the call to OnPropertyChanged("Baz") from the two property handlers:

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

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

However, if you want the Foo and Bar properties to be updated through Binding, then you'd be back to @Franck's suggestion of calling this method twice and the two properties are updated individually. In that case, it seems as though you'll just have to put up with the Baz property being notified twice.

Upvotes: 4

Gope
Gope

Reputation: 1778

insert a value changed check in your setter like:

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

Upvotes: 1

Related Questions