如何在 C# 中 PropertyChanged 事件的 INotifyPropertyChanged 实现中捕获旧值和新值

Ume*_*ase 7 c#

我需要在 PropertyChanged 事件处理程序中捕获旧值、新值和属性名称。INotifyPropertyChanged 的​​默认实现仅提供属性的名称。因此,在互联网上搜索后,我在这里发现了类似的问题,属性的扩展实现已更改。

以下是该 Q 和接口声明的链接:

NotifyPropertyChanged 事件,其中事件参数包含旧值

public interface INotifyPropertyChangedExtended<T>
{
    event PropertyChangedExtendedEventHandler<T> PropertyChanged;
}
Run Code Online (Sandbox Code Playgroud)

公共委托 void PropertyChangedExtendedEventHandler(对象发送者, PropertyChangedExtendedEventArgs e);

上面的接口将解决我的问题,但是我不明白如何在我的实体类上实现通用接口,因为 T 将根据属性的数据类型而改变。

谁能帮助我理解,是否可以用 T 参数实现这个接口。这个示例的实现将会非常有帮助。

预先感谢您的帮助。

乌梅什

编辑 #1:根据 Peter 的回复,发布更新的代码,这对于想要在 PropertyChanged 事件中捕获旧值和新值的人可能有用。

    public class PropertyChangedExtendedEventArgs : PropertyChangedEventArgs
{
    public string OldValue { get; set; }

    public string NewValue { get; set; }

    public PropertyChangedExtendedEventArgs(string propertyName, string oldValue, string newValue) : base(propertyName)
    {
        OldValue = oldValue;
        NewValue = newValue;
    }
}

    //
// Summary:
//     Notifies clients that a property value has changed.
public interface INotifyPropertyChangedEnhanced
{
    //
    // Summary:
    //     Occurs when a property value changes.
    event PropertyChangedEventHandlerEnhanced PropertyChanged;
}

public delegate void PropertyChangedEventHandlerEnhanced(object sender, PropertyChangedExtendedEventArgs e);

public abstract class BindableBase : INotifyPropertyChangedEnhanced
{
    public event PropertyChangedEventHandlerEnhanced PropertyChanged;

    protected bool SetProperty<T>(ref T storage, T value, [CallerMemberName] 
    string propertyName = null)
    {
        if (Equals(storage, value))
        {
            return false;
        }

        var oldValue = storage;
        storage = value;
        this.OnPropertyChanged(oldValue, value, propertyName);
        return true;
    }
    protected void OnPropertyChanged<T>(T oldValue, T newValue, [CallerMemberName] string propertyName = null)
    {
        this.PropertyChanged?.Invoke(this, new PropertyChangedExtendedEventArgs(propertyName, oldValue?.ToString(), newValue?.ToString()));
    }
}
Run Code Online (Sandbox Code Playgroud)

Erh*_*run 8

只需实现您自己的 PropertyChangedEventArgs。

没有必要实现新的接口。

这个解决方案有效。这是多态性的好处之一

public class PropertyChangedExtendedEventArgs : PropertyChangedEventArgs
{
        public virtual object OldValue { get; private set; }
        public virtual object NewValue { get; private set; }

        public PropertyChangedExtendedEventArgs(string propertyName, object oldValue, 
               object newValue)
               : base(propertyName)
        {
            OldValue = oldValue;
            NewValue = newValue;
        }
    }

public class NotifyObject : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged(string propertyName, object oldvalue, object newvalue)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedExtendedEventArgs(propertyName, oldvalue, newvalue));
        }
    }



public class Person : NotifyObject
    {
        private int _name;
        public int Name
        {
            get { return _name; }
            set
            {
                var oldValue = _name;
                _name = value;
                NotifyPropertyChanged("Name", oldValue, value);

            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

和你的视图模型

Person person = new Person();
person.PropertyChanged += person_PropertyChanged;

  void person_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            var args = e as PropertyChangedExtendedEventArgs;
            //do whatever you want
        }
Run Code Online (Sandbox Code Playgroud)


Pet*_*iho 2

我不明白如何在实体类上实现通用接口,因为 T 会根据属性的数据类型而改变

这是正确的。您正在查看的答案实际上并不是那么好的答案,因为它包含无法编译或没有意义的代码。

通过传递继承非泛型类 PropertyChanged的泛型参数类来引发非泛型事件的基本思想PropertyChangedEventArgs本身是可以的。它应该在你的情况下工作得很好。

但!您将无法实现答案提出的通用接口,因为(正如您已经注意到的)当属性具有不同类型时,该接口不起作用。事实上,您正在查看的答案甚至无法使用该接口进行编译,因为它们的事件引发方法本身是通用的,并且引发非通用PropertyChanged事件(该方法将与通用接口不兼容),并且它们不必费心去实际实现他们的泛型接口(如果他们尝试过,他们会注意到泛型方法不适用于泛型接口......方法的类型参数T与接口的类型参数不同T)。

不幸的是,高票答案是这样写的。它有一些有用的想法,但它也有完全不可行的想法,并且只会让正在寻找类似答案的人(即最想阅读和使用答案的人)感到困惑。