patterncsharpCritical
Implementing INotifyPropertyChanged - does a better way exist?
Viewed 0 times
existbetterinotifypropertychangeddoeswayimplementing
Problem
Microsoft should have implemented something snappy for
I think it makes a lot of sense to do it. Or are there any complications to do it?
Can we ourselves implement something like 'notify' in our properties. Is there a graceful solution for implementing
If not can we write something to auto-generate the piece of code to raise
INotifyPropertyChanged, like in the automatic properties, just specify {get; set; notify;}I think it makes a lot of sense to do it. Or are there any complications to do it?
Can we ourselves implement something like 'notify' in our properties. Is there a graceful solution for implementing
INotifyPropertyChanged in your class or the only way to do it is by raising the PropertyChanged event in each property.If not can we write something to auto-generate the piece of code to raise
PropertyChanged event?Solution
Without using something like postsharp, the minimal version I use uses something like:
Each property is then just something like:
which isn't huge; it can also be used as a base-class if you want. The
or even easier with C# 5:
which can be called like this:
with which the compiler will add the
C# 6.0 makes the implementation easier:
...and now with C#7:
And, with C# 8 and Nullable reference types, it would look like this:
public class Data : INotifyPropertyChanged
{
// boiler-plate
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField(ref T field, T value, string propertyName)
{
if (EqualityComparer.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
// props
private string name;
public string Name
{
get { return name; }
set { SetField(ref name, value, "Name"); }
}
}Each property is then just something like:
private string name;
public string Name
{
get { return name; }
set { SetField(ref name, value, "Name"); }
}which isn't huge; it can also be used as a base-class if you want. The
bool return from SetField tells you if it was a no-op, in case you want to apply other logic.or even easier with C# 5:
protected bool SetField(ref T field, T value,
[CallerMemberName] string propertyName = null)
{...}which can be called like this:
set { SetField(ref name, value); }with which the compiler will add the
"Name" automatically.C# 6.0 makes the implementation easier:
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}...and now with C#7:
protected void OnPropertyChanged(string propertyName)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
protected bool SetField(ref T field, T value,[CallerMemberName] string propertyName = null)
{
if (EqualityComparer.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
private string name;
public string Name
{
get => name;
set => SetField(ref name, value);
}And, with C# 8 and Nullable reference types, it would look like this:
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
protected bool SetField(ref T field, T value, [CallerMemberName] string propertyName = "")
{
if (EqualityComparer.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
private string name;
public string Name
{
get => name;
set => SetField(ref name, value);
}Code Snippets
public class Data : INotifyPropertyChanged
{
// boiler-plate
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected bool SetField<T>(ref T field, T value, string propertyName)
{
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
// props
private string name;
public string Name
{
get { return name; }
set { SetField(ref name, value, "Name"); }
}
}private string name;
public string Name
{
get { return name; }
set { SetField(ref name, value, "Name"); }
}protected bool SetField<T>(ref T field, T value,
[CallerMemberName] string propertyName = null)
{...}set { SetField(ref name, value); }protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}Context
Stack Overflow Q#1315621, score: 768
Revisions (0)
No revisions yet.