Levantar um evento sempre que o valor de uma propriedade for alterado?

Existe uma propriedade, denominada ImageFullPath1

public string ImageFullPath1 {get; set; } 

Vou triggersr um evento sempre que seu valor for alterado. Estou ciente de alterar INotifyPropertyChanged , mas quero fazer isso com events.

A interface INotifyPropertyChanged é implementada com events. A interface tem apenas um membro, PropertyChanged , que é um evento no qual os consumidores podem se inscrever.

A versão que Richard postou não é segura. Veja como implementar essa interface com segurança:

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

Observe que isso faz o seguinte:

  • Abstrai os methods de notificação de alteração de propriedade para que você possa aplicá-lo facilmente a outras propriedades;

  • Faz uma cópia do delegado PropertyChanged antes de tentar invocá-lo (falhar ao fazer isso criará uma condição de corrida).

  • Corretamente implementa a interface INotifyPropertyChanged .

Se você deseja criar adicionalmente uma notificação para uma propriedade específica que está sendo alterada, adicione o seguinte código:

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

Em seguida, adicione a linha OnImageFullPathChanged(EventArgs.Empty) após a linha OnPropertyChanged("ImageFullPath") .

Uma vez que temos .Net 4.5 existe o CallerMemberAttribute , que permite se livrar da string codificada para o nome da propriedade no código-fonte:

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

Eu uso basicamente os mesmos padrões que Aaronaught, mas se você tem muitas propriedades, pode ser bom usar um pouco de mágica de método genérico para tornar seu código um pouco mais seco.

 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 } 

Normalmente eu também faço o OnPropertyChanged método virtual para permitir sub-classs para substituí-lo para capturar as alterações de propriedade.

Levantar um evento quando uma propriedade é alterada é precisamente o que INotifyPropertyChanged faz. Há um membro obrigatório para implementar INotifyPropertyChanged e esse é o evento PropertyChanged. Qualquer coisa que você implementasse provavelmente seria idêntica a essa implementação, então não há vantagem em não usá-la.

 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*/); } } 

Dito isto, concordo completamente com o Ryan. Esse cenário é precisamente porque existe INotifyPropertyChanged.

Se você alterar sua propriedade para usar um campo de apoio (em vez de uma propriedade automática), poderá fazer o seguinte:

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