berry wer
berry wer

Reputation: 647

INotifyPropertyChanged with derive class

I have this class:

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; }
    }
}

And the derive class:

public class MyFile : MyFileInfo
{

}

So every time my _bytesSent has changed i want to notify:

public event PropertyChangedEventHandler PropertyChanged;

public virtual void NotifyPropertyChange(string propertyName)
{
    var handler = PropertyChanged;
    if (handler != null)
        handler(this, new PropertyChangedEventArgs(propertyName));
}

Using this:

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

So my question is: where should i declare this event ? in the base class on the one that derive

Upvotes: 0

Views: 825

Answers (3)

Wulfy
Wulfy

Reputation: 1

It probably wouldn't hurt to have a base class that accumulates some useful operations associated with INotifyPropertyChanged. I usually use something akin to the following:

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
    }

The calls are styled to allow you to do most things in one line thus:

public int PropertyName
{
    get { return _propertyName; }
    set { ChangeAndNotify(ref _propertyName, value); }
}

or

public int PropertyName
{
    get { return _propertyName; }
    set { ChangeAndNotify(ref _propertyName, value, "PropertyName", "AdditionalRelatedPropertyName"); }
}

or

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

Upvotes: 0

Alexandre Borela
Alexandre Borela

Reputation: 1626

The base class, it should work normally. One more thing, change your method to this:

public virtual void NotifyPropertyChange([CallerMemberName]string propertyName = null)
{
    PropertyChanged?.Invoke (this, new PropertyChangedEventArgs (propertyName));
}

This way, you can call it without specifying the property name like so:

NotifyPropertyChange ();

The compiler will fill the property name for you. You can still specify the property:

NotifyPropertyChange ("Property");
NotifyPropertyChange (nameof (Property));

As it was said by Liero, you should use the standard naming OnPropertyChanged scheme. Note: The ? (Safe navigation operator) and nameof is only available in C# 6.

Then everytime you want a property to notify the UI that it got changed, you do:

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

Upvotes: 0

Liero
Liero

Reputation: 27350

by convention, you should define it in the base class as protected virtual with name "OnEventName":

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

Upvotes: 2

Related Questions