如何在 C# 6.0 中实现 INotifyPropertyChanged
本文关键字:实现 INotifyPropertyChanged | 更新日期: 2023-09-27 18:36:01
这个
问题的答案已经被编辑为在C# 6.0中,INotifyPropertyChanged可以通过以下OnPropertyChanged过程实现:
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
但是,从该答案中不清楚相应的属性定义应该是什么。使用此构造时,INotifyPropertyChanged 的完整实现在 C# 6.0 中是什么样子的?
合并各种更改后,代码将如下所示。我用评论强调了更改的部分以及每个部分如何提供帮助
public class Data : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
//C# 6 null-safe operator. No need to check for event listeners
//If there are no listeners, this will be a noop
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
// C# 5 - CallMemberName means we don't need to pass the property's name
protected bool SetField<T>(ref T field, T value,
[CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(field, value))
return false;
field = value;
OnPropertyChanged(propertyName);
return true;
}
private string name;
public string Name
{
get { return name; }
//C# 5 no need to pass the property name anymore
set { SetField(ref name, value); }
}
}
我在项目中使用相同的逻辑。我的应用程序中的所有视图模型都有一个基类:
using System.ComponentModel;
using System.Runtime.CompilerServices;
public class PropertyChangedBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
每个视图模型都继承自此类。现在,在每个属性的二传手中,我只需要调用OnPropertyChanged()
。
public class EveryViewModel : PropertyChangedBase
{
private bool initialized;
public bool Initialized
{
get
{
return initialized;
}
set
{
if (initialized != value)
{
initialized = value;
OnPropertyChanged();
}
}
}
为什么有效?
编译器会自动填充[CallerMemberName]
,其中包含调用此函数的成员的名称。当我们从 Initialized
调用OnPropertyChanged
时,编译器将nameof(Initialized)
作为参数来OnPropertyChanged
要记住的另一个重要细节
框架要求PropertyChanged
和要绑定到的所有属性都public
。
我知道
这个问题很旧,但这是我的实现
可绑定使用字典作为属性存储。为子类添加必要的重载以使用 ref 参数管理其自己的支持字段非常简单。
- 没有魔术字符串
- 无反射
- 可以改进以禁止默认字典查找
代码:
public class Bindable : INotifyPropertyChanged
{
private Dictionary<string, object> _properties = new Dictionary<string, object>();
/// <summary>
/// Gets the value of a property
/// <typeparam name="T"></typeparam>
/// <param name="name"></param>
/// <returns></returns>
protected T Get<T>([CallerMemberName] string name = null)
{
object value = null;
if (_properties.TryGetValue(name, out value))
return value == null ? default(T) : (T)value;
return default(T);
}
/// <summary>
/// Sets the value of a property
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value"></param>
/// <param name="name"></param>
protected void Set<T>(T value, [CallerMemberName] string name = null)
{
if (Equals(value, Get<T>(name)))
return;
_properties[name] = value;
OnPropertyChanged(name);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
像这样使用
public class Item : Bindable
{
public Guid Id { get { return Get<Guid>(); } set { Set<Guid>(value); } }
}