Вызвать событие всякий раз, когда значение свойства изменилось?
есть свойство, оно называется 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); } } }