2012-05-04 11 views
8

Forse qui è già una domanda del genere, ma non l'ho trovata.Auto-sottoscrizione a PropertyChanged o metodo aggiuntivo call in setter?

Ho un'applicazione MVVM e nel mio ViewModel Devo eseguire alcune azioni aggiuntive sulle modifiche di alcune proprietà (ad esempio, se View le modifica). Quale approccio è migliore nella tua mente e perché?

1 ° - Aggiungi AdditionalAction chiamata al setter

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

2 ° - Auto-sottoscrivere 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(); 
    } 
} 

Immaginate, che non ho problema di prestazioni o 10.000 oggetti. È solo View e ViewModel. Cos'è meglio? Il primo codice è "più piccolo" e ha meno spese generali, ma il secondo (a mio avviso) è più chiaro e posso usare i frammenti di codice per il codice delle proprietà di generazione automatica. Ancora più - nel 2 ° caso posso scrivere nel gestore di eventi qualcosa di simile:

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

dove On è di classe-helper.

Quindi, cosa c'è di meglio nella tua mente e perché?

aggiornamento:

OK, sembra che ho trovato ancora un approccio:

3 - aggiungere "punto di estensione" in 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(); 
    } 
} 

In questo modo non usiamo l'evento, ma tutte le "azioni aggiuntive" sono chiamate dallo stesso "punto di estensione". "Un posto per tutte le azioni di addizione" è meglio di "un flusso di lavoro non trasparente"?

+2

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

+0

sidenote: considerare l'utilizzo di un metodo di supporto per mettere le tre linee in setter dei vostri oggetti da uno, restituire un booleano se la proprietà è cambiata. Più breve e nessuna duplicazione. per esempio 'if (RaisePropertyChanged (ref _MyProperty, value, o => o.MyProperty)) AdditionalAction();' – stijn

+0

@Tergiver quali sono le differenze tra la tua strada e la mia seconda via? Sono uguali: scrivi codice aggiuntivo non nel "setter" ma nel "gestore di eventi" - il metodo "OnXXX" da questo punto di vista è lo stesso dell'abbonamento automatico all'evento. Quindi, dal tuo punto di vista la mia domanda è: "È meglio chiamare' AdditionalAction' dal setter o dal metodo OnPropertyChanged? " (anche se in realtà non esiste il metodo OnPropertyChanged) – chopikadze

risposta

3

avrei sicuramente andare per il primo metodo:

  • E 'chiaro
  • è esplicita nel suo flusso e l'intenzione
  • evita strano (IMO) di sottoscrizione di sé

I "vantaggi" di second, che consentono di utilizzare proprietà generate automaticamente, non valgono la chiarezza del flusso di esecuzione della prima scatola, imo.

Spero che questo aiuti.

+0

cosa ne pensi del 3 ° modo? – chopikadze

+0

@chopikadze: sembra buono, perché * potrebbe * supportare il refactoring del codice, se ci si libera della stringa: propertyName in qualche modo. – Tigran

3

Ecco il modello "solito". Ciò consente di inserire il codice specifico della proprietà all'interno del metodo OnX e consente alle classi derivate di fare lo stesso. Non c'è bisogno di una dichiarazione di switch di grandi dimensioni, a meno che ovviamente tu non sia l'ascoltatore esterno, ma questo è il par per il corso per 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

Grazie mille per il tuo aiuto, ho contrassegnato la risposta di @Tigran solo perché ha più voti, ma apprezzo molto la nostra discussione! – chopikadze