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驱动的应用程序中形成瓶颈。
听起来你想要将INotifyPropertyChanging
与INotifyPropertyChanged
结合使用。 Msdn Documentation http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanging.aspx
如果您只想要旧值,则可以在更改属性值之前调用该事件。 但这将是这个事件通常如何使用的背离,所以我会为它创建一个专用的接口和args。
不,你必须从头开始创建自己的。
我曾经在我的研究项目Granite中做同样的事情,但我开始意识到这不值得付出代价。 我计算了太多与我合作的属性,并且为了引发事件而必须运行它们两次太昂贵了。