PropertyChangedEvent запускается несколько раз

1

У меня есть класс с несколькими свойствами. Когда они изменяются, возникает 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. Я только хочу позвонить ему один раз. Есть ли хороший способ обойти это?

Теги:
wpf
event-handling
events

2 ответа

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 вам необходимо уведомить об этом интерфейс.

Его значение может быть изменено при изменении значений свойств Foo или Bar... поэтому вам нужно будет уведомить об этом интерфейс, если любой из них изменится, как и у вас.

Теперь @Franck прокомментировал, что вам нужно, чтобы с установщика Property 1 запускался метод обновления Property 2, который путем изменения инициирует его собственное изменение свойства. Подумайте об этом на минутку... предположительно, вам нужно будет вызвать тот же метод из обоих Foo свойств Foo или Bar чтобы он работал.

Однако на самом деле произойдет то, что когда значения Foo и Bar будут изменены, метод будет вызываться дважды, и поэтому уведомление INotifyPropertyChanged будет по-прежнему вызываться дважды, хотя теперь оно происходит от установщика Baz... так ясно, это без улучшения.

Однако есть еще один вариант, который может сработать для вас. Чтобы это сработало, вам нужно добавить вспомогательный метод, который будет обновлять значения свойств Foo или Bar и уведомлять интерфейс 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 обновлялись посредством Binding, вы вернетесь к предложению @Franck о вызове этого метода дважды, и два свойства обновляются индивидуально. В этом случае кажется, что вам просто придется мириться с тем, что имущество Baz было уведомлено дважды.

  • 1
    Хорошее решение для чистого мульти уведомления. @torbonde, если вы планируете сохранить свой первоначальный способ, я предлагаю это изменение.
  • 0
    Спасибо большое! Мне очень нравится мульти-уведомление! Тем не менее, я не думаю, что понимаю последнюю часть вашего ответа. Где бы я позвонил в UpdateBaz ?
Показать ещё 3 комментария
0

вставьте значение с измененной проверкой в свой сеттер, например:

set
{
   if(value != [yourfield])
   {
      yourfield = value;
      OnPropertyChanged(Yourfield);
   }
}
  • 0
    И как это поможет?
  • 0
    @KamilT: На самом деле, в любом случае, это хороший стиль, но его отсутствие может привести к ненужным обновлениям, приводящим к вызовам PropChange. Я еще не видел его код ...
Показать ещё 6 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню