NotifyPropertyChanged事件,其中event args包含旧值 [英] NotifyPropertyChanged event where event args contain the old value

查看:199
本文介绍了NotifyPropertyChanged事件,其中event 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< 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆