有没有什么方法可以避免这种情况。我有很多类绑定到DataGridViews,它们只是一些具有默认getter和setter的简单属性集合。因此,这些类非常简单。现在我需要为它们实现INotifyPropertyChanged接口,这将大大增加代码量。有没有任何类可以继承,以避免编写所有这些无聊的代码?我想象中我可以从某个类继承我的类,并使用一些属性进行修饰,它就会自动完成。这可行吗?
我很清楚面向方面编程,但我更愿意用面向对象的方式来做。
我很清楚面向方面编程,但我更愿意用面向对象的方式来做。
这要看情况,你可以使用PostSharp编写这样的属性,并由织入器进行重写; 然而,我会倾向于手动执行 - 可能使用一种通用方法来处理数据更新,即。
private string name;
public string Name {
get { return name; }
set { Notify.SetField(ref name, value, PropertyChanged, this, "Name"); }
}
使用:
public static class Notify {
public static bool SetField<T>(ref T field, T value,
PropertyChangedEventHandler handler, object sender, string propertyName)
{
if(!EqualityComparer<T>.Default.Equals(field,value)) {
field = value;
if(handler!=null) {
handler(sender, new PropertyChangedEventArgs(propertyName));
}
return true;
}
return false;
}
}
abstract class Container : INotifyPropertyChanged
{
Dictionary<string, object> values;
protected object this[string name]
{
get {return values[name]; }
set
{
values[name] = value;
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
}
class Foo : Container
{
public int Bar
{
{get {return (int) this["Bar"]; }}
{set { this["Bar"] = value; } }
}
}
这里有一个类似于Marc的解决方案,已经扩展以允许多个属性onpropertychanges和多个RaiseCanExecuteChanged
最简单的使用示例
string _firstName;
public string FirstName
{
get { return _firstName; }
set { OnPropertyChanged(ref _firstName, value, "FirstName"); }
}
高级示例,使用多个属性更新和多个命令
string _firstName;
public string FirstName
{
get { return _firstName; }
set { OnPropertyChanged(ref _firstName, value, "FirstName", "FullName", Command1, Command2); }
}
高级示例调用 OnPropertychanged 在 firstname 和 fullname 上,并且还调用 command1 和 command2 的 RaiseCanExecuteChanged。
基本 ViewModel 代码
protected void OnPropertyChanged<T>(ref T field, T value, params object[] updateThese)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
OnPropertyChanged(updateThese);
}
}
protected void OnPropertyChanged(params object[] updateThese)
{
if (PropertyChanged != null)
{
foreach (string property in updateThese.Where(property => property is string))
PropertyChanged(this, new PropertyChangedEventArgs(property));
foreach (DelegateCommand<object> command in updateThese.Where(property => property is DelegateCommand<object>))
command.RaiseCanExecuteChanged();
}
}
没有AOP,我认为没有简单的方法将其应用到现有类中。无论如何,您至少都需要更改所有属性。
我使用一个继承INotifyPropertyChanged的基类,并具有OnPropertyChanged(string propertyName)方法来触发事件。然后,我使用Visual Studio Code片段创建属性,自动在属性设置器中调用OnPropertyChanged。
我刚刚发现了ActiveSharp - Automatic INotifyPropertyChanged,虽然我还没有使用它,但它看起来很不错。
引用自它的网站...
public int Foo
{
get { return _foo; }
set { SetValue(ref _foo, value); } // <-- no property name here
}
对leepie进行改进。
values
字典中没有这样的元素的情况(导致KeyNotFoundException
)避免传递属性的名称
(使用CallerMemberName
属性)(["name"])
。用法:
public class MyViewModel : PropertyChangedHelper
{
public int Bar
{
get => GetProperty<int>();
set => SetProperty<int>(value);
}
}
代码:
public class PropertyChangedHelper : INotifyPropertyChanged
{
private readonly Dictionary<string, object> _values = new Dictionary<string, object>();
public event PropertyChangedEventHandler PropertyChanged;
public T GetProperty<T>([CallerMemberName] string propertyName = "")
{
EnsureElement<T>(propertyName);
return (T) _values[propertyName];
}
public void SetProperty<T>(object value, [CallerMemberName] string propertyName = "")
{
EnsureElement<T>(propertyName);
if (_values[propertyName] == value)
{
return;
}
_values[propertyName] = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void EnsureElement<T>(string propertyName)
{
if (!_values.ContainsKey(propertyName))
{
_values.Add(propertyName, default(T));
}
}
}
来自: devto 里面还有基准测试。