有没有办法避免这种情况。我有很多绑定到DataGridViews的类,它们只是带有默认getter和setter的简单属性集合。所以这些类非常简单。现在我需要为它们实现INotifyPropertyChanged接口,这将增加很多代码量。 是否有任何类可以继承以避免编写所有这些无聊的代码?我认为我可以从某个类继承我的类,并用一些属性装饰属性,它会发挥魔力。这可能吗?
我很清楚面向方面编程,但我宁愿以面向对象的方式进行。
答案 0 :(得分:9)
取决于;您可以使用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;
}
}
答案 1 :(得分:4)
创建容器基类,例如:
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; } }
}
}
注意:非常简化的代码
答案 2 :(得分:1)
如果没有AOP,我认为没有一种简单的方法可以将这种方法改进现有的课程。无论你如何做,你至少都需要改变你的所有属性。
我使用一个继承INotifyPropertyChanged的基类和一个OnPropertyChanged(string propertyName)方法来触发事件。然后,我使用Visual Studio代码片段创建在属性设置器中自动调用OnPropertyChanged的属性。
答案 3 :(得分:1)
以下是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); }
}
高级示例调用OnProperty在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();
}
}
答案 4 :(得分:0)
答案 5 :(得分:0)
使用代码gen(比如,T4)是另一种方式。请查看讨论:Automatic INotifyPropertyChanged Implementation through T4 code generation?。
我使用这种方法,效果很好。
答案 6 :(得分:0)
我刚刚找到ActiveSharp - Automatic INotifyPropertyChanged,我还没有使用它,但它看起来不错。
引用它的网站......
发送房产更改通知 没有指定属性名称 字符串。
相反,写下这样的属性:
public int Foo
{
get { return _foo; }
set { SetValue(ref _foo, value); } // <-- no property name here
}
请注意,不需要将属性的名称包含在字符串中。 ActiveSharp可靠而正确地为自己确定了这一点。它的工作原理是您的属性实现通过ref传递了支持字段(_foo)。 (ActiveSharp使用“by ref”调用来标识传递了哪个支持字段,并从字段中识别属性)。
答案 7 :(得分:0)
leepie 的改进。
values
字典中没有这样的元素的情况(导致 KeyNotFoundException)
avoid passing the name
的属性(使用 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 那里也有基准。