Aumentare un evento ogni volta che il valore di una proprietà cambia?

C’è una proprietà, si chiama ImageFullPath1

public string ImageFullPath1 {get; set; } 

Sto andando a sparare a un evento ogni volta che il suo valore cambia. Sono consapevole di cambiare INotifyPropertyChanged , ma voglio farlo con gli eventi.

L’interfaccia INotifyPropertyChanged è implementata con eventi. L’interfaccia ha un solo membro, PropertyChanged , che è un evento a cui i consumatori possono iscriversi.

La versione pubblicata da Richard non è sicura. Ecco come implementare in modo sicuro questa interfaccia:

 public class MyClass : INotifyPropertyChanged { private string imageFullPath; protected void OnPropertyChanged(PropertyChangedEventArgs e) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, e); } protected void OnPropertyChanged(string propertyName) { OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); } public string ImageFullPath { get { return imageFullPath; } set { if (value != imageFullPath) { imageFullPath = value; OnPropertyChanged("ImageFullPath"); } } } public event PropertyChangedEventHandler PropertyChanged; } 

Nota che questo fa le seguenti cose:

  • Abstracts i metodi di notifica di modifica delle proprietà in modo da poterlo applicare facilmente ad altre proprietà;

  • Fa una copia del delegato PropertyChanged prima di tentare di invocarlo (non riuscendo a farlo creerà una condizione di competizione).

  • Implementa correttamente l’interfaccia INotifyPropertyChanged .

Se si desidera inoltre creare una notifica per la modifica di una proprietà specifica , è ansible aggiungere il seguente codice:

 protected void OnImageFullPathChanged(EventArgs e) { EventHandler handler = ImageFullPathChanged; if (handler != null) handler(this, e); } public event EventHandler ImageFullPathChanged; 

Quindi aggiungere la riga OnImageFullPathChanged(EventArgs.Empty) dopo la riga OnPropertyChanged("ImageFullPath") .

Dal momento che abbiamo .Net 4.5 esiste CallerMemberAttribute , che permette di sbarazzarsi della stringa hard-coded per il nome della proprietà nel codice sorgente:

  protected void OnPropertyChanged( [System.Runtime.CompilerServices.CallerMemberName] string propertyName = "") { OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); } public string ImageFullPath { get { return imageFullPath; } set { if (value != imageFullPath) { imageFullPath = value; OnPropertyChanged(); } } } 

Uso in gran parte gli stessi pattern di Aaronaught, ma se hai molte proprietà potrebbe essere bello usare un po ‘di metodo magico per rendere il tuo codice un po’ più ASCIUTTO

 public class TheClass : INotifyPropertyChanged { private int _property1; private string _property2; private double _property3; protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) { PropertyChangedEventHandler handler = PropertyChanged; if(handler != null) { handler(this, e); } } protected void SetPropertyField(string propertyName, ref T field, T newValue) { if(!EqualityComparer.Default.Equals(field, newValue)) { field = newValue; OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); } } public int Property1 { get { return _property1; } set { SetPropertyField("Property1", ref _property1, value); } } public string Property2 { get { return _property2; } set { SetPropertyField("Property2", ref _property2, value); } } public double Property3 { get { return _property3; } set { SetPropertyField("Property3", ref _property3, value); } } #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; #endregion } 

Di solito, inoltre, rendono virtuale il metodo OnPropertyChanged per consentire alle sottoclassi di sovrascriverlo per rilevare le modifiche alle proprietà.

Alzare un evento quando una proprietà cambia è esattamente ciò che fa INotifyPropertyChanged. C’è un membro richiesto per implementare INotifyPropertyChanged e questo è l’evento PropertyChanged. Qualunque cosa tu abbia implementato tu stesso sarebbe probabilmente identico a quell’implementazione, quindi non c’è alcun vantaggio nel non usarlo.

 public event EventHandler ImageFullPath1Changed; public string ImageFullPath1 { get { // insert getter logic } set { // insert setter logic // EDIT -- this example is not thread safe -- do not use in production code if (ImageFullPath1Changed != null && value != _backingField) ImageFullPath1Changed(this, new EventArgs(/*whatever*/); } } 

Detto questo, sono completamente d’accordo con Ryan. Questo scenario è precisamente il motivo per cui esiste INotifyPropertyChanged.

Se si modifica la proprietà per utilizzare un campo di supporto (anziché una proprietà automatica), è ansible effettuare le seguenti operazioni:

 public event EventHandler ImageFullPath1Changed; private string _imageFullPath1 = string.Empty; public string ImageFullPath1 { get { return imageFullPath1 ; } set { if (_imageFullPath1 != value) { _imageFullPath1 = value; EventHandler handler = ImageFullPathChanged; if (handler != null) handler(this, e); } } }