Wpf INotifyPropertyChanged与派生类

Wpf INotifyPropertyChanged与派生类,wpf,inotifypropertychanged,Wpf,Inotifypropertychanged,我有这门课: public class MyFileInfo : INotifyPropertyChanged { private string _file; private int _bytesSent; public MyFileInfo(string file) { } public string File { get { return _file; } set { _file = value;

我有这门课:

public class MyFileInfo : INotifyPropertyChanged
{
    private string _file;
    private int _bytesSent;

    public MyFileInfo(string file)
    {

    }

    public string File
    {
        get { return _file; }
        set { _file = value; }
    }

    public int BytesSent
    {
        get { return _bytesSent; }
        set { _bytesSent= value; }
    }
}
和派生类:

public class MyFile : MyFileInfo
{

}
因此,每次我的
\u bytesSent
发生更改时,我都要通知:

public event PropertyChangedEventHandler PropertyChanged;

public virtual void NotifyPropertyChange(string propertyName)
{
    var handler = PropertyChanged;
    if (handler != null)
        handler(this, new PropertyChangedEventArgs(propertyName));
}
使用此选项:

public static int PropertyName
{
    get { return _propertyName; }
    set
    {
        _totalPacketsSent = value;
        NotifyPropertyChange("...");
    }
}

所以我的问题是:我应该在哪里宣布这个事件?在派生基类的基类上,它应该正常工作。还有一件事,将您的方法更改为:

public virtual void NotifyPropertyChange([CallerMemberName]string propertyName = null)
{
    PropertyChanged?.Invoke (this, new PropertyChangedEventArgs (propertyName));
}
这样,您就可以在不指定属性名称的情况下调用它,如下所示:

NotifyPropertyChange ();
编译器将为您填写属性名称。您仍然可以指定属性:

NotifyPropertyChange ("Property");
NotifyPropertyChange (nameof (Property));
正如Liero所说,您应该使用标准的命名OnPropertyChanged方案。 注:是什么?(安全导航操作员)和名称仅在C#6中可用

然后,每当您希望某个属性通知UI它已更改时,您都会执行以下操作:

public String MyTestProperty
{
    get {return _MyTestProperty;}
    set {
        _MyTestProperty = value;
        NotifyPropertyChange ();
    }
}

按照惯例,您应该在基类中将其定义为名为“OnEventName”的受保护虚拟机:


如果有一个基类来积累一些与
INotifyPropertyChanged
相关联的有用操作,可能不会有什么坏处。我通常使用类似于以下内容的内容:

public class NotifiableBase : INotifyPropertyChanged
    {
        #region Utility methods

        /// <summary>
        /// Notify of a property change and optional additional dependencies.
        /// </summary>
        public void Notify([CallerMemberName] string propertyName = null, params string[] additionalNames)
        {
            OnPropertyChanged(propertyName);
            foreach (var name in additionalNames)
            {
                OnPropertyChanged(name);
            }
        }

        /// <summary>
        /// Makes a change to the supplied reference if different.
        /// If different, notify of a property change and optional additional dependencies.
        /// </summary>
        public bool ChangeAndNotify<T>(ref T toChange, T newValue, [CallerMemberName] string propertyName = null, params string[] additionalNames)
        {
            var cmp = EqualityComparer<T>.Default;
            if (cmp.Equals(toChange, newValue) == false)
            {
                toChange = newValue;
                OnPropertyChanged(propertyName);
                foreach (var name in additionalNames)
                {
                    OnPropertyChanged(name);
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// Makes a change to the supplied reference if different.
        /// If different, notify of a property change and optional additional dependencies then call action.
        /// </summary>
        public bool ChangeAndNotifyWithAction<T>(ref T toChange, T newValue, Action action, [CallerMemberName] string propertyName = null, params string[] additionalNames)
        {
            var ret = ChangeAndNotify(ref toChange, newValue, propertyName, additionalNames);
            if (ret)
            {
                action();
            }
            return ret;
        }

        #endregion

        #region INotifyPropertyChanged implementation

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }


我没有否决,但在本例中,
CallerMemberName
不是最佳选择,因为他想通知
TotalPacketsSent
属性已从
PropertyName
属性更改,因此您必须指定参数。是的,我不是暗示是您,我甚至不知道有新的答案,所以我认为这个人正在寻找它,一定是一个肇事逃逸的XD,但我只是忘记了派生类正在做工作,并且这个类中的属性正在更改,所以我认为它应该在派生类中。我说的对吗?如果您正在更改MyProperty=Value之类的属性,它应该可以正常工作,因为您正在属性的Set方法内调用NotifyPropertyChange,所有要发出通知的属性都必须在其值更改后调用此方法。例如,BytesSent属性,如果在_bytesSent=value之后将集合更改为调用NotifyPropertyChange,它将通知UI bytesSent已更改。这篇文章比较老,所以没有使用后来发布的C#功能。使用表达式也是表示属性(,)的方便方法。
public class NotifiableBase : INotifyPropertyChanged
    {
        #region Utility methods

        /// <summary>
        /// Notify of a property change and optional additional dependencies.
        /// </summary>
        public void Notify([CallerMemberName] string propertyName = null, params string[] additionalNames)
        {
            OnPropertyChanged(propertyName);
            foreach (var name in additionalNames)
            {
                OnPropertyChanged(name);
            }
        }

        /// <summary>
        /// Makes a change to the supplied reference if different.
        /// If different, notify of a property change and optional additional dependencies.
        /// </summary>
        public bool ChangeAndNotify<T>(ref T toChange, T newValue, [CallerMemberName] string propertyName = null, params string[] additionalNames)
        {
            var cmp = EqualityComparer<T>.Default;
            if (cmp.Equals(toChange, newValue) == false)
            {
                toChange = newValue;
                OnPropertyChanged(propertyName);
                foreach (var name in additionalNames)
                {
                    OnPropertyChanged(name);
                }
                return true;
            }
            return false;
        }

        /// <summary>
        /// Makes a change to the supplied reference if different.
        /// If different, notify of a property change and optional additional dependencies then call action.
        /// </summary>
        public bool ChangeAndNotifyWithAction<T>(ref T toChange, T newValue, Action action, [CallerMemberName] string propertyName = null, params string[] additionalNames)
        {
            var ret = ChangeAndNotify(ref toChange, newValue, propertyName, additionalNames);
            if (ret)
            {
                action();
            }
            return ret;
        }

        #endregion

        #region INotifyPropertyChanged implementation

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }
public int PropertyName
{
    get { return _propertyName; }
    set { ChangeAndNotify(ref _propertyName, value); }
}
public int PropertyName
{
    get { return _propertyName; }
    set { ChangeAndNotify(ref _propertyName, value, "PropertyName", "AdditionalRelatedPropertyName"); }
}
public int PropertyName
{
    get { return _propertyName; }
    set { ChangeAndNotify(ref _propertyName, value, () => SomeActionOnSuccess()); }
}