属性 实现 INotify 时的 Getters 和 Setters 属性改变了吗?
Property Getters and Setters when implementing INotifyPropertyChanged?
我正在尝试为很多 classes 实现 INotifyPropertyChanged,并且每个 classes 都有很多很多属性。我一直在关注这个 MSDN documentation 如何实现 INofifyPropertyChanged,但是在 class 具有许多属性的情况下,他们的说明似乎并不实用。
目前我的大部分属性都使用简写:
public DateTime? DateClosed { get; set; }
但是文档说我需要在每个 setter 方法中添加以下内容:
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("DateClosed");
这意味着我需要为 get 方法声明一个主体,并声明私有变量来处理实际的属性获取和设置。像这样:
private DateTime? _dateOfIncident = null;
public DateTime? DateClosed
{
get { return _dateOfIncident; }
set
{
_dateOfIncident= value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("DateClosed");
}
}
有人知道解决这个问题的方法吗?
我不确定您是否会在这里找到解决方法。自动属性,正如您现在使用的那样,实际上只是一个编译器 shorthand,无论如何最终都会转换为带有支持字段的完整属性(至少,据我所知)。
INPC 的使用是一种例行程序,与正常 属性 的职责有点不同。它通知订阅者(通常是您的观点 XAML)所讨论的 属性 已更改或正在更改。
tl;dr -- 您不会绕过必须将自动属性重写为具有支持字段的完整属性。但是像 MVVMLight 这样的工具包有一些很棒的 Visual Studio 代码片段可以使这个过程相对较快。最终你甚至可以这样做:
private string _someString;
public string SomeString
{
get { return _someString;}
set
{
//Set returns bool, so you can trigger other logic on it!
Set(() => SomeString, ref _someString, value);
}
}
这为您提供了一些巧妙的功能:
- 强命名(与您示例中的魔术字符串不同)
Set
仅在值不同时触发 INPC 事件
Set
returns 布尔值,因此您可以在值更改时执行更多操作
MVVMLight 的优点在于您不必使用它的所有功能,甚至不必实施 MVVM 模式。它有很多不错的 'tools' 你可以利用。
有很多模式可以做到,或者您可以购买一个工具like PostSharp来为您完成。
例如,这是一种方法:
public abstract class BaseNotifyPropertyChanged : INotifyPropertyChanged
{
private Dictionary<string, object> _valueStore = new Dictionary<string, object>();
public event PropertyChangedEventHandler PropertyChanged;
protected T Get<T>([CallerMemberName]string property = null)
{
object value = null;
if (!_valueStore.TryGetValue(property, out value))
return default(T);
return (T)value;
}
protected void Set<T>(T value, [CallerMemberName]string property = null)
{
_valueStore[property] = value;
OnPropertyChangedInternal(property);
}
protected void OnPropertyChanged([CallerMemberName]string property = null)
{
OnPropertyChangedInternal(property);
}
private void OnPropertyChangedInternal(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
然后您从 类:
继承
public class PlainOldObject : BaseNotifyPropertyChanged
{
public int MyProperty
{
get { return Get<int>(); }
set { Set(value); }
}
}
它会为您处理后备存储和一切。您可能想要添加逻辑以仅在 属性 实际更改(比较引用或值)时调用 OnPropertyChangedInternal
,但我将把它留给您作为练习。
只需使用 Observable Object class。您无需创建 DateTime
属性,而是创建 ObservableObject<DateTime>
,然后只需绑定到 DateClosed.Value
.
几个 类 可以很容易地更改为实现 INotifyPropertyChanged
。但是既然你说你有 很多 of 类 有很多属性,手动甚至使用模板完成这件事是一个真正的负担。
您真正需要的是一个可以为您完成的工具,因此我向您展示 Fody 它是 NotifyPropertyChanged 插件。 Fody 所做的是在编译时在代码之间编织一些额外的代码。您唯一需要做的就是在要实现的 类 上添加一个属性 INotifyPropertyChanged
,其余的都为您完成。
[ImplementPropertyChanged]
public class Person
{
public string GivenNames { get; set; }
public string FamilyName { get; set; }
public string FullName
{
get
{
return string.Format("{0} {1}", GivenNames, FamilyName);
}
}
}
我正在尝试为很多 classes 实现 INotifyPropertyChanged,并且每个 classes 都有很多很多属性。我一直在关注这个 MSDN documentation 如何实现 INofifyPropertyChanged,但是在 class 具有许多属性的情况下,他们的说明似乎并不实用。
目前我的大部分属性都使用简写:
public DateTime? DateClosed { get; set; }
但是文档说我需要在每个 setter 方法中添加以下内容:
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("DateClosed");
这意味着我需要为 get 方法声明一个主体,并声明私有变量来处理实际的属性获取和设置。像这样:
private DateTime? _dateOfIncident = null;
public DateTime? DateClosed
{
get { return _dateOfIncident; }
set
{
_dateOfIncident= value;
// Call OnPropertyChanged whenever the property is updated
OnPropertyChanged("DateClosed");
}
}
有人知道解决这个问题的方法吗?
我不确定您是否会在这里找到解决方法。自动属性,正如您现在使用的那样,实际上只是一个编译器 shorthand,无论如何最终都会转换为带有支持字段的完整属性(至少,据我所知)。
INPC 的使用是一种例行程序,与正常 属性 的职责有点不同。它通知订阅者(通常是您的观点 XAML)所讨论的 属性 已更改或正在更改。
tl;dr -- 您不会绕过必须将自动属性重写为具有支持字段的完整属性。但是像 MVVMLight 这样的工具包有一些很棒的 Visual Studio 代码片段可以使这个过程相对较快。最终你甚至可以这样做:
private string _someString;
public string SomeString
{
get { return _someString;}
set
{
//Set returns bool, so you can trigger other logic on it!
Set(() => SomeString, ref _someString, value);
}
}
这为您提供了一些巧妙的功能:
- 强命名(与您示例中的魔术字符串不同)
Set
仅在值不同时触发 INPC 事件Set
returns 布尔值,因此您可以在值更改时执行更多操作
MVVMLight 的优点在于您不必使用它的所有功能,甚至不必实施 MVVM 模式。它有很多不错的 'tools' 你可以利用。
有很多模式可以做到,或者您可以购买一个工具like PostSharp来为您完成。
例如,这是一种方法:
public abstract class BaseNotifyPropertyChanged : INotifyPropertyChanged
{
private Dictionary<string, object> _valueStore = new Dictionary<string, object>();
public event PropertyChangedEventHandler PropertyChanged;
protected T Get<T>([CallerMemberName]string property = null)
{
object value = null;
if (!_valueStore.TryGetValue(property, out value))
return default(T);
return (T)value;
}
protected void Set<T>(T value, [CallerMemberName]string property = null)
{
_valueStore[property] = value;
OnPropertyChangedInternal(property);
}
protected void OnPropertyChanged([CallerMemberName]string property = null)
{
OnPropertyChangedInternal(property);
}
private void OnPropertyChangedInternal(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
然后您从 类:
继承public class PlainOldObject : BaseNotifyPropertyChanged
{
public int MyProperty
{
get { return Get<int>(); }
set { Set(value); }
}
}
它会为您处理后备存储和一切。您可能想要添加逻辑以仅在 属性 实际更改(比较引用或值)时调用 OnPropertyChangedInternal
,但我将把它留给您作为练习。
只需使用 Observable Object class。您无需创建 DateTime
属性,而是创建 ObservableObject<DateTime>
,然后只需绑定到 DateClosed.Value
.
几个 类 可以很容易地更改为实现 INotifyPropertyChanged
。但是既然你说你有 很多 of 类 有很多属性,手动甚至使用模板完成这件事是一个真正的负担。
您真正需要的是一个可以为您完成的工具,因此我向您展示 Fody 它是 NotifyPropertyChanged 插件。 Fody 所做的是在编译时在代码之间编织一些额外的代码。您唯一需要做的就是在要实现的 类 上添加一个属性 INotifyPropertyChanged
,其余的都为您完成。
[ImplementPropertyChanged]
public class Person
{
public string GivenNames { get; set; }
public string FamilyName { get; set; }
public string FullName
{
get
{
return string.Format("{0} {1}", GivenNames, FamilyName);
}
}
}