Как избежать реализации INotifyPropertyChanged вручную - PullRequest
8 голосов
/ 28 июня 2010

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

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

Ответы [ 7 ]

9 голосов
/ 28 июня 2010

Это зависит;Вы можете использовать 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;
    }
}
4 голосов
/ 28 июня 2010

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

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

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

1 голос
/ 01 августа 2011

Вот аналогичное решение для 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, измененный для имени и полного имени, а также вызывает 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();
    }
}
1 голос
/ 28 июня 2010

Без АОП, я не думаю, что есть простой способ дооснастить это для существующих классов.Как бы вы это ни делали, вам по крайней мере придется менять все свои свойства.

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

0 голосов
/ 01 июня 2011

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

Цитата с его веб-сайта ...


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

Вместо этого напишите свойства, подобные этому:

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

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

0 голосов
/ 28 июня 2010

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

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

0 голосов
/ 28 июня 2010

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

...