Есть свойство, оно называется ImageFullPath1
public string ImageFullPath1 {get; set; }
Я собираюсь запустить событие, когда его значение изменится. Я знаю об изменении INotifyPropertyChanged
, но я хочу делать это с событиями.
Есть свойство, оно называется ImageFullPath1
public string ImageFullPath1 {get; set; }
Я собираюсь запустить событие, когда его значение изменится. Я знаю об изменении INotifyPropertyChanged
, но я хочу делать это с событиями.
Интерфейс 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, но если у вас много свойств, было бы неплохо использовать немного общего метода магии, чтобы сделать ваш код немного более СУХИМЫМ
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);
}
}
}
Ткач Fody делает большую часть работы за вас. Он внедряет INotifyPropertyChanging в ваш код во время компиляции: