Вызвать событие всякий раз, когда значение свойства изменилось?
есть свойство, оно называется ImageFullPath1
public string ImageFullPath1 {get; set; }
Я собираюсь запустить событие всякий раз, когда его значение изменилось. Я в курсе изменений INotifyPropertyChanged
, но я хочу сделать это с событиями.
5 ответов:
The
INotifyPropertyChanged
интерфейс и реализованы с событиями. Интерфейс имеет только один член,PropertyChanged
, который является событием, на которое потребители могут подписаться.версия, которую опубликовал Ричард, небезопасна. Вот как безопасно реализовать этот интерфейс:
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; }
обратите внимание, что это делает следующие вещи:
абстрагирует свойство-изменить методы уведомления, так что вы можете легко применить это к другим свойства;
копировать
PropertyChanged
делегат до попытка вызвать его (в противном случае это создаст условие гонки).правильно реализует
INotifyPropertyChanged
интерфейс.если вы хотите дополнительно создать уведомление для конкретные свойство изменяется, вы можете добавить следующий код:
protected void OnImageFullPathChanged(EventArgs e) { EventHandler handler = ImageFullPathChanged; if (handler != null) handler(this, e); } public event EventHandler ImageFullPathChanged;
затем добавить линия
OnImageFullPathChanged(EventArgs.Empty)
после строкиOnPropertyChanged("ImageFullPath")
.так как у нас есть .Net 4.5 существует
CallerMemberAttribute
, что позволяет избавиться от жестко закодированной строки для имени свойства в исходном коде: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, но если у вас много свойств, было бы неплохо использовать немного общего метода magic, чтобы сделать ваш код немного больше сухой
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); } } }