NotifyPropertyChanged事件,其中event args包含旧值 [英] NotifyPropertyChanged event where event args contain the old value
问题描述
是否有一个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< T> :PropertyChangedEventArgs
{
public virtual T OldValue {get;私人集合}
public virtual T NewValue {get;私人集合
public PropertyChangedExtendedEventArgs(string propertyName,T oldValue,T newValue)
:base(propertyName)
{
OldValue = oldValue;
NewValue = newValue;
}
}
扩展PropertyChanged界面
如果程序员想要创建一个强制通知属性包含旧值和新值的事件,那么它们只需要实现以下界面:
//摘要:通知客户端属性值正在更改,但包括扩展事件信息
/ *当您希望强制包含旧和
*新值时,将使用以下NotifyPropertyChanged接口。 (用户必须提供PropertyChangedExtendedEventArgs,不允许PropertyChangedEventArgs。)* /
public interface INotifyPropertyChangedExtended< T>
{
事件PropertyChangedExtendedEventHandler< T>的PropertyChanged;
}
public delegate void PropertyChangedExtendedEventHandler< T>(object sender,PropertyChangedExtendedEventArgs< T> e);
示例1 / p>
用户现在可以指定一个更高级的 NotifyPropertyChanged
方法,允许属性设置器传入其旧值: p>
public String testString
{
get {return testString; }
set
{
String temp = testString;
testValue2 = value;
NotifyPropertyChanged(TestString,temp,value);
}
}
您的新 NotifyPropertyChanged
方法看起来像这样:
protected void NotifyPropertyChanged< T>(string propertyName,T oldvalue,T newvalue )
{
OnPropertyChanged(this,new PropertyChangedExtendedEventArgs< T>(propertyName,oldvalue,newvalue));
}
And 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< T>(表达式< Func< T>表达式,ref T字段,T值)
{
if(field == null ||!field.Equals(value))
{
T oldValue = field;
field = value;
OnPropertyChanged(this,new PropertyChangedExtendedEventArgs< T>(GetPropertyName(expression),oldValue,value));
}
}
protected string GetPropertyName< T>(表达式< Func< T>>表达式)
{
MemberExpression memberExpression =(MemberExpression)expression.Body;
return memberExpression.Member.Name;
}
性能
如果出现性能问题,请参阅以下问题:实施NotifyPropertyChanged没有魔术字符串。
总之,开销很小。添加旧值并切换到扩展事件约为15%的减速,仍然允许在每秒一百万个属性通知的顺序上,并且切换到lambda表达式是减速的5倍,允许每次大约十万个属性通知第二。这些数字远远无法在任何UI驱动的应用程序中形成瓶颈。
Is there an INotifyPropertyChanged-like interface where the event args contains the old value of the property being changed, or do I have to extend that interface to create one?
For example:
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) );
}
I would also settle for a PropertyChanging-like event which provides this information, whether or not it supports e.Cancel.
As indicated by the answers, I had to implement my own solution. For the benefit of others, I've presented it here:
The Extended PropertyChanged Event
This event has been specially designed to be backwards compatible with old propertyChanged events. It can be used interchangeably with the simple PropertyChangedEventArgs by callers. Of course, in such cases, it is the responsibility of the event handler to check if the passed PropertyChangedEventArgs can be downcast to a PropertyChangedExtendedEventArgs, if they want to use it. No downcasting is necessary if all they're interested in is the PropertyName property.
public class PropertyChangedExtendedEventArgs<T> : 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;
}
}
The Extended PropertyChanged Interface
If, the programmer wanted to create an event that forces the notifying properties to include an old value and a new value, they need only implement the following interface:
// 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<T>
{
event PropertyChangedExtendedEventHandler<T> PropertyChanged;
}
public delegate void PropertyChangedExtendedEventHandler<T>(object sender, PropertyChangedExtendedEventArgs<T> e);
Example 1
The user can now specify a more advanced NotifyPropertyChanged
method that allows property setters to pass in their old value:
public String testString
{
get { return testString; }
set
{
String temp = testString;
testValue2 = value;
NotifyPropertyChanged("TestString", temp, value);
}
}
Where your new NotifyPropertyChanged
method looks like this:
protected void NotifyPropertyChanged<T>(string propertyName, T oldvalue, T newvalue)
{
OnPropertyChanged(this, new PropertyChangedExtendedEventArgs<T>(propertyName, oldvalue, newvalue));
}
And OnPropertyChanged
is the same as always:
public virtual void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler(sender, e);
}
Example 2
Or if you prefer to use lambda expressions and do away with hard-coded property name strings entirely, you can use the following:
public String TestString
{
get { return testString; }
private set { SetNotifyingProperty(() => TestString, ref testString, value); }
}
Which is supported by the following magic:
protected void SetNotifyingProperty<T>(Expression<Func<T>> expression, ref T field, T value)
{
if (field == null || !field.Equals(value))
{
T oldValue = field;
field = value;
OnPropertyChanged(this, new PropertyChangedExtendedEventArgs<T>(GetPropertyName(expression), oldValue, value));
}
}
protected string GetPropertyName<T>(Expression<Func<T>> expression)
{
MemberExpression memberExpression = (MemberExpression)expression.Body;
return memberExpression.Member.Name;
}
Performance
If performance is a concern, see this question: Implementing NotifyPropertyChanged without magic strings.
In summary, the overhead is minimal. Adding the old value and switching to the extended event is about a 15% slowdown, still allowing for on the order of one million property notifications per second, and switching to lambda expressions is a 5 times slowdown allowing for approximately one hundred thousand property notifications per second. These figures are far from being able to form a bottleneck in any UI-driven application.
这篇关于NotifyPropertyChanged事件,其中event args包含旧值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!