当一个属性的值改变时引发一个事件?

有一个属性,它被命名为ImageFullPath1

public string ImageFullPath1 {get; set; } 

每当它的价值发生变化,我都会开火。 我知道改变INotifyPropertyChanged ,但我想要做的事情。

INotifyPropertyChanged接口用事件实现的。 该接口只有一个成员PropertyChanged ,这是消费者可以订阅的事件。

Richard发布的版本不安全。 这里是如何安全地实现这个接口:

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

请注意,这会做以下事情:

  • 摘要属性更改通知方法,以便您可以轻松地将其应用于其他属性;

  • 尝试调用它之前创buildPropertyChanged委托的副本(如果不这样做将会创build竞争条件)。

  • 正确实现INotifyPropertyChanged接口。

如果您还想为正在更改的特定属性创build通知,则可以添加以下代码:

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

然后在行OnImageFullPathChanged(EventArgs.Empty) OnPropertyChanged("ImageFullPath")之后添加行OnImageFullPathChanged(EventArgs.Empty) OnPropertyChanged("ImageFullPath")

由于我们有.Net 4.5,所以存在CallerMemberAttribute ,它允许摆脱源代码中属性名称的硬编码string:

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

我使用的模式基本上和Aaronaught一样,但是如果你有很多的属性,可以使用一些通用的方法来使你的代码变得更干

 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<T>(string propertyName, ref T field, T newValue) { if(!EqualityComparer<T>.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 } 

通常我也使OnPropertyChanged方法变为虚拟,以允许子类覆盖它来捕捉属性更改。

当属性更改时引发事件正是INotifyPropertyChanged所做的事情。 有一个必需的成员实现INotifyPropertyChanged,这是PropertyChanged事件。 你自己实现的任何东西都可能与该实现相同,所以不使用它是没有好处的。

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

这就是说,我完全同意瑞恩。 这种情况正是INotifyPropertyChanged存在的原因。

如果将属性更改为使用后台字段(而不是自动属性),则可以执行以下操作:

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