2012-05-04 1 views
8

Может быть, здесь уже такой вопрос, но я его не нашел.Self-subscribe to PropertyChanged или метод добавления метода в setter?

У меня есть приложение MVVM, и в моем ViewModel я должен выполнить некоторые дополнительные действия по изменению некоторых свойств (например, если View меняет их). Какой подход лучше на ваш взгляд и почему?

первый - Добавить AdditionalAction вызов сеттер

public class ViewModel: INotifyPropertyChanged 
{ 
    private int _MyProperty; 

    public int MyProperty 
    { 
    get { return _MyProperty; } 
    set 
    { 
     if (_MyProperty == value) return; 
     _MyProperty = value; 
     RaisePropertyChanged(() => MyProperty); 

     // --- ADDITIONAL CODE --- 
     AdditionalAction(); 
    } 
    } 
} 

второй - Self подписаться на INotifyPropertyChanged

public class ViewModel: INotifyPropertyChanged 
{ 
    public ViewModel() 
    { 
    // --- ADDITIONAL CODE --- 
    PropertyChanged += OnPropertyChanged; 
    } 

    private int _MyProperty; 

    public int MyProperty 
    { 
    get { return _MyProperty; } 
    set 
    { 
     if (_MyProperty == value) return; 
     _MyProperty = value; 
     RaisePropertyChanged(() => MyProperty); 
    } 
    } 

    void PropertyChanged(object sender, PropertyChangedEventArgs e) 
    { 
    // --- ADDITIONAL CODE --- 
    if (e.PropertyName == "MyProperty") 
     AdditionalAction(); 
    } 
} 

Представьте себе, что у меня нет проблем с производительностью или 10 000 объектов. Это просто View и ViewModel. Что лучше? Первый код «меньше» и имеет меньше накладных расходов, но второй (на мой взгляд) более ясен, и я могу использовать фрагменты кода для кода свойств автогенерации. Даже больше - во 2-м случае я могу написать в обработчик события что-то вроде:

On.PropertyChanged(e, p => p.MyProperty, AdditionalAction); 

где On является класс-хелпер.

Итак, что лучше на вашем уме и почему?

ОБНОВЛЕНО:

ОК, похоже, я нашел еще один подход:

3rd - добавить "точку расширения" в RaisePropertyChanged:

public class NotificationObject : INotifyPropertyChanged 
{ 
    void RaisePropertyChanged(Expression<...> property) 
    { 
    // ... Raise PropertyChanged event 
    if (PropertyChanged != null) 
     // blah-blah 

    // Call extension point 
    OnPropertyChanged(property.Name); 
    } 

    public virtual OnPropertyChanged(string propertyName) 
    { 
    } 
} 

public class ViewModel: NotificationObject 
{ 
    private int _MyProperty; 

    public int MyProperty 
    { 
    get { return _MyProperty; } 
    set 
    { 
     if (_MyProperty == value) return; 
     _MyProperty = value; 
     RaisePropertyChanged(() => MyProperty); 
    } 
    } 

    override OnPropertyChanged(string propertyName) 
    { 
    if (propertyName == "MyProperty") 
     AdditionalAction(); 
    } 
} 

Этот путь мы не используем событие, но все «дополнительные действия» вызываются из одной и той же «точки расширения». Является ли «одно место для всех дополнительных действий» лучше, чем «непрозрачный рабочий процесс»?

+2

http://tergiver.wordpress.com/2011/01/20/self-subscription-is-asinine/ – Tergiver

+0

Sidenote: рассмотреть возможность использования вспомогательного метода, чтобы поместить три строки в инкубаторе ваших свойств к одному, возвращая логическое значение, если свойство изменилось. Сокращение и отсутствие дублирования. например 'if (RaisePropertyChanged (ref _MyProperty, value, o => o.MyProperty)) AdditionalAction();' – stijn

+0

@Тергивер, в чем разница между вашим путем и моим вторым способом? Они одинаковые - вы пишете дополнительный код не в «сеттере», а в «обработчике событий» - метод «OnXXX» с этой точки зрения совпадает с самоподпиской на событие. Итак, с моей точки зрения, мой вопрос: «Лучше ли вызывать« AdditionalAction »из сеттера или из метода OnPropertyChanged?» (даже если на самом деле нет метода OnPropertyChanged) – chopikadze

ответ

3

Я определенно идти в первый метод:

  • это ясно
  • это явно в его потоке и намерение
  • избегает странно (IMO) самостоятельной подписки

«Преимущества» второго, который позволяет использовать автогенерируемые свойства, не стоит ясности потока выполнения первого случая, imo.

Надеюсь, это поможет.

+0

Что вы думаете о третьем? – chopikadze

+0

@chopikadze: кажется хорошим, потому что он * может * поддерживать рефакторинг кода, если вы избавитесь от строки: propertyName в некотором роде. – Tigran

3

Описание «Обычная» модель. Это позволяет помещать специфический для свойства код внутри метода OnX и позволяет производным классам делать то же самое. Нет необходимости в большом объявлении switch, если, конечно, вы не являетесь внешним слушателем, но это соответствует курсу для INotifyPropertyChanged.

public class NotificationObject : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 
    protected void FirePropertyChanged(PropertyChangedEventArgs e) 
    { 
     PropertyChangedEventHandler handler = PropertyChanged; 
     if (handler != null) 
      handler(this, e); 
    } 
} 

public class ViewModel : NotificationObject 
{ 
    private int _MyProperty1; 
    public int MyProperty1 
    { 
     get { return _MyProperty1; } 
     set 
     { 
      if (value != _MyProperty1) 
      { 
       _MyProperty1 = value; 
       OnMyProperty1Changed(new PropertyChangedEventArgs("MyProperty1")); 
      } 
     } 
    } 

    protected virtual void OnMyProperty1Changed(PropertyChangedEventArgs e) 
    { 
     FirePropertyChanged(e); 
    } 

    private int _MyProperty2; 
    public int MyProperty2 
    { 
     get { return _MyProperty2; } 
     set 
     { 
      if (value != _MyProperty2) 
      { 
       _MyProperty2 = value; 
       OnMyProperty2Changed(new PropertyChangedEventArgs("MyProperty2")); 
      } 
     } 
    } 

    protected virtual void OnMyProperty2Changed(PropertyChangedEventArgs e) 
    { 
     FirePropertyChanged(e); 
    } 
} 
+0

Большое спасибо за вашу помощь, я отметил ответ @Tigran только потому, что у него больше голосов, но я очень ценю наше обсуждение! – chopikadze