Как лучше всего вызвать событие PropertyChanged INotifyPropertyChanged?

Когда вы реализуете интерфейс INotifyPropertyChanged, вы несете ответственность за вызов события PropertyChanged каждый раз, когда свойство обновляется в классе.

Обычно это приводит к следующему коду:

    public class MyClass: INotifyPropertyChanged

        private bool myfield;
        public bool MyField
        {
            get { return myfield; }
            set
            {
                if (myfield == value)
                    return;
                myfield = value;
                OnPropertyChanged(new PropertyChangedEventArgs("MyField"));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler h = PropertyChanged;
            if (h != null)
                h(this, e);
        }
   }

Это 12 строк на свойство.

Было бы намного проще, если бы можно было украсить автоматические свойства следующим образом:

[INotifyProperty]
public double MyField{ get; set; }

Но, к сожалению, это невозможно (см. этот пост на msdn для пример)

Как я могу уменьшить количество кода, необходимого для каждого свойства?


person Brann    schedule 28.01.2009    source источник
comment
см. stackoverflow.com/questions/1329138/ для проверенного компилятором способа реализации INotifyPropertyChanged. Избегайте использования имен свойств в виде волшебной строки.   -  person Ian Ringrose    schedule 26.08.2009
comment
кроме того, вы можете добавить шаблонный код во время выполнения, если используете контейнер IoC: stackoverflow.com/questions/488587/ (предупреждение: это исказит ваш разум, если вы не знакомы с IoC)   -  person fostandy    schedule 31.03.2011
comment
Просто добавлю: PostSharp теперь поддерживает это.   -  person It'sNotALie.    schedule 10.06.2013
comment
Более свежий (и очень популярный) ответ можно найти здесь: stackoverflow.com/questions/1315621/   -  person kmote    schedule 28.06.2016


Ответы (3)


На самом деле это всего 3-4 строки на свойство; остальные строки амортизируются по всем "уведомляющим" свойствам:

class Person : INotifyPropertyChanged
{
    #region INotifyPropertyChanged: Shared bit
    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(PropertyChangedEventArgs e)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, e);
    }
    #endregion

    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set
        {
            if (_firstName == value)
                return;
            _firstName = value;
            OnPropertyChanged(new PropertyChangedEventArgs("FirstName"));
        }
    }

    // Ditto for other properties
}

Вы можете попробовать что-то вроде следующего, которое частично разделяет нагрузку:

private string _firstName;
public string FirstName
{
    get { return _firstName; }
    set { SetNotifyingProperty("FirstName", ref _firstName, value); }
}
private void SetNotifyingProperty<T>(string propertyName,
                                     ref T field, T value)
{
    if (value.Equals(field))
        return;
    field = value;
    OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
person Roger Lipscombe    schedule 16.02.2009
comment
Хорошая идея. Кстати, еще одна проблема с этим кодом заключается в том, что новый экземпляр PropertyChangedEventArgs создается каждый раз при изменении свойства. EventArgs можно сохранить в переменной members для дальнейшего использования. - person Brann; 17.02.2009

На данный момент я пишу это в своем классе:

 //AUTOGENERATE INotifyProperty
 private bool myfield;

И я написал небольшой инструмент, который генерирует весь необходимый код свойств в частичном классе. Это ни в коем случае не изящное решение, но оно работает :)

person Brann    schedule 28.01.2009

Имеет смысл передать на аутсорсинг.

Напишите класс (ObservableObject) со следующим кодом:

class ObservableObject : INotifyPropertyChanged
{
  public event PropertyChangedEventHandler PropertyChanged;

  protected void OnPropertyChanged(string name)
  {
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
  }
}

Все классы, производные от этого класса, могут получить доступ к методу благодаря protected.

Пример:

class Example : ObservableObject
{
  //propfull
  private string name;
  public string Name
  {
    get {return name;}
    set 
    {
      name = value;
      OnPropertyChanged(nameof(Name));
    }
  }
}
person BigShady    schedule 16.08.2019