Как избежать реализации INotifyPropertyChanged вручную

есть ли способ избежать этого. У меня есть много классов, которые привязаны к DataGridViews, и они просто простая коллекция свойств с геттером и сеттером по умолчанию. Поэтому эти занятия очень просты. Теперь мне нужно реализовать интерфейс INotifyPropertyChanged для них, который значительно увеличит объем кода. Есть ли класс, который я могу наследовать, чтобы избежать написания всего этого скучного кода? Я представляю, что я могу наследовать свои классы от некоторого класса и украсить свойства некоторые атрибуты, и это сделает магию. Это возможно?

Я хорошо знаю аспектно-ориентированное программирование, но я бы предпочел сделать это объектно-ориентированным способом.

7 ответов


создайте базовый класс контейнера, например:

abstract class Container : INotifyPropertyChanged
{
  Dictionary<string, object> values;

  protected object this[string name]
  {
    get {return values[name]; }
    set 
    { 
      values[name] = value;
      PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
  }
}

class Foo : Container
{
  public int Bar 
  {
    {get {return (int) this["Bar"]; }}
    {set { this["Bar"] = value; } }
  }
}

Примечание: очень упрощенный код


это зависит; вы можете использовать PostSharp написать такой атрибут,переписан Ткачом; однако, я бы соблазнился просто сделать это вручную-возможно, используя общий метод для обработки обновлений данных, т. е.

private string name;
public string Name {
    get { return name; }
    set { Notify.SetField(ref name, value, PropertyChanged, this, "Name"); }
}

С:

public static class Notify {
    public static bool SetField<T>(ref T field, T value,
         PropertyChangedEventHandler handler, object sender, string propertyName)
    {
        if(!EqualityComparer<T>.Default.Equals(field,value)) {
            field = value;
            if(handler!=null) {
                handler(sender, new PropertyChangedEventArgs(propertyName));
            }
            return true;
        }
        return false;
    }
}

без AOP, я не думаю, что есть простой способ модифицировать это для ваших существующих классов. Как бы вы это ни сделали, вам, по крайней мере, придется изменить все свои свойства.

Я использую базовый класс, наследующий INotifyPropertyChanged с методом OnPropertyChanged(string propertyName) для запуска события. Затем я использую фрагмент кода Visual Studio для создания свойств, которые автоматически вызывают OnPropertyChanged в сеттере свойств.


вот аналогичное решение для Marc, которое было расширено, чтобы разрешить несколько свойств onpropertychanges и несколько RaiseCanExecuteChanged

простой пример использования

string _firstName;
public string FirstName
{
    get { return _firstName; }
    set { OnPropertyChanged(ref _firstName, value, "FirstName"); }
}

расширенный пример использования нескольких обновлений свойств и нескольких команд

string _firstName;
public string FirstName
{
    get { return _firstName; }
    set { OnPropertyChanged(ref _firstName, value, "FirstName", "FullName", Command1, Command2); }
}

расширенный пример вызывает OnProperty изменен на firstname и fullname, а также вызывает RaiseCanExecuteChanged для command1 и command2

базовый ViewModel код

protected void OnPropertyChanged<T>(ref T field, T value, params object[] updateThese)
{
    if (!EqualityComparer<T>.Default.Equals(field, value))
    {
        field = value;
        OnPropertyChanged(updateThese);
    }
}

protected void OnPropertyChanged(params object[] updateThese)
{
    if (PropertyChanged != null)
    {
        foreach (string property in updateThese.Where(property => property is string))
            PropertyChanged(this, new PropertyChangedEventArgs(property));

        foreach (DelegateCommand<object> command in updateThese.Where(property => property is DelegateCommand<object>))
            command.RaiseCanExecuteChanged();
    }
}

Если вы поддаетесь AOP, вы можете попробовать использовать PostSharp. Поиск PostSharp INotifyPropertyChanged и вы найдете много статей, объясняющих это, таких как этой и этой.


использование кода gen (скажем,T4) есть еще один способ. Проверьте обсуждение по адресу:автоматическая реализация INotifyPropertyChanged через генерацию кода T4?.

Я использую этот метод, и он работает хорошо.


Я только что нашел ActiveSharp-Автоматический INotifyPropertyChanged, Я еще не использовал его, но он выглядит хорошо.

процитировать с его веб-сайта...


отправлять уведомления об изменении свойств без указания имени свойства в качестве строка.

вместо этого напишите такие свойства:

public int Foo
{
    get { return _foo; }
    set { SetValue(ref _foo, value); }  // <-- no property name here
}

обратите внимание, что нет необходимости содержать имя свойства как строку. ActiveSharp надежно и правильно вычисляет это для себя. Он работает на основе того факта, что реализация вашего свойства передает поле поддержки (_foo) по ref. (ActiveSharp использует этот вызов "по ref", чтобы определить, какое резервное поле было передано, и из поля он идентифицирует свойство).