NotifyPropertyChanged事件,其中事件args包含旧值

是否有类似INotifyPropertyChanged的接口,其中事件args包含要更改的属性的旧值,或者我是否必须扩展该接口以创建一个?

例如:

public String ProcessDescription { get { return _ProcessDescription; } set { if( value != ProcessDescription ) { String oldValue = _ProcessDescription; _ProcessDescription = value; InvokePropertyChanged("ProcessDescription", oldvalue); } } } InvokePropertyChanged(String PropertyName, OldValue) { this.PropertyChanged( new ExtendedPropertyChangedEventArgs(PropertyName, OldValue) ); } 

我也会讨论类似PropertyChanging的事件,它提供这些信息,无论它是否支持e.Cancel。

如答案所示,我必须实施自己的解决方案。 为了别人的利益,我在这里提出了:

扩展PropertyChanged事件

此活动专门设计为向后兼容旧的propertyChanged事件。 它可以与调用者使用简单的PropertyChangedEventArgs互换使用。 当然,在这种情况下,事件处理程序负责检查传递的PropertyChangedEventArgs是否可以向下转换为PropertyChangedExtendedEventArgs,如果他们想要使用它。 如果他们感兴趣的是PropertyName属性,则不需要向下转换。

 public class PropertyChangedExtendedEventArgs : PropertyChangedEventArgs { public virtual T OldValue { get; private set; } public virtual T NewValue { get; private set; } public PropertyChangedExtendedEventArgs(string propertyName, T oldValue, T newValue) : base(propertyName) { OldValue = oldValue; NewValue = newValue; } } 

扩展PropertyChanged接口

如果程序员想要创建一个强制通知属性包含旧值和新值的事件,则只需要实现以下接口:

 // Summary: Notifies clients that a property value is changing, but includes extended event infomation /* The following NotifyPropertyChanged Interface is employed when you wish to enforce the inclusion of old and * new values. (Users must provide PropertyChangedExtendedEventArgs, PropertyChangedEventArgs are disallowed.) */ public interface INotifyPropertyChangedExtended { event PropertyChangedExtendedEventHandler PropertyChanged; } public delegate void PropertyChangedExtendedEventHandler(object sender, PropertyChangedExtendedEventArgs e); 

例1

用户现在可以指定更高级的NotifyPropertyChanged方法,该方法允许属性设置器传递其旧值:

 public String testString { get { return testString; } set { String temp = testString; testValue2 = value; NotifyPropertyChanged("TestString", temp, value); } } 

您的新NotifyPropertyChanged方法如下所示:

 protected void NotifyPropertyChanged(string propertyName, T oldvalue, T newvalue) { OnPropertyChanged(this, new PropertyChangedExtendedEventArgs(propertyName, oldvalue, newvalue)); } 

OnPropertyChanged和以下一样:

 public virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(sender, e); } 

例2

或者,如果您更喜欢使用lambda表达式并完全取消硬编码的属性名称字符串,则可以使用以下命令:

 public String TestString { get { return testString; } private set { SetNotifyingProperty(() => TestString, ref testString, value); } } 

以下魔术支持以下内容:

 protected void SetNotifyingProperty(Expression> expression, ref T field, T value) { if (field == null || !field.Equals(value)) { T oldValue = field; field = value; OnPropertyChanged(this, new PropertyChangedExtendedEventArgs(GetPropertyName(expression), oldValue, value)); } } protected string GetPropertyName(Expression> expression) { MemberExpression memberExpression = (MemberExpression)expression.Body; return memberExpression.Member.Name; } 

性能

如果需要考虑性能,请参阅此问题: 在没有魔术字符串的情况下实现NotifyPropertyChanged 。

总之,开销很小。 添加旧值并切换到扩展事件大约减慢15%,仍然允许每秒大约一百万个属性通知,并且切换到lambda表达式是5倍减速,允许每个大约十万个属性通知第二。 这些数字远远不能在任何UI驱动的应用程序中形成瓶颈。

听起来你想要将INotifyPropertyChangingINotifyPropertyChanged结合使用。 Msdn Documentation http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanging.aspx

如果您只想要旧值,则可以在更改属性值之前调用该事件。 但这将是这个事件通常如何使用的背离,所以我会为它创建一个专用的接口和args。

不,你必须从头开始创建自己的。

我曾经在我的研究项目Granite中做同样的事情,但我开始意识到这不值得付出代价。 我计算了太多与我合作的属性,并且为了引发事件而必须运行它们两次太昂贵了。