0

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

berry wer
  • 637
  • 2
  • 12
  • 25
  • Here's a full but simple example on a [blog post](http://techfilth.blogspot.co.nz/2010/02/streamlining-property-notifications-in.html) I wrote. That post is older so doesn't use C# features that were released later. Using expressions is also a convenient way to represent the property ([example 1](http://stackoverflow.com/a/143611/109702), [example 2](http://stackoverflow.com/a/1316566/109702)). – slugster Jul 27 '15 at 13:27

3 Answers3

2

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));
}
Liero
  • 25,216
  • 29
  • 151
  • 297
0

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 ();
    }
}
Alexandre Borela
  • 1,576
  • 13
  • 21
  • I have not downvoted, but in this case `CallerMemberName` is not the best option, because he wants to notify that `TotalPacketsSent` property has changed from `PropertyName` property, so you have to specify the argument anyway. – Liero Jul 27 '15 at 12:39
  • Yeah, I wasn't implying it was you, I didn't even knew there was a new answer, so I though the person was looking it yet, must be a hit and run XD – Alexandre Borela Jul 27 '15 at 12:46
  • But i just forget that the derive class is doing the work and the properties is changing in this class so it should be in the derive class i think. am i right ? – berry wer Jul 27 '15 at 12:47
  • If you are changing the properties like MyProperty = Value, it should work normally because you are calling NotifyPropertyChange inside the Set method of the property, all properties that you want to have notification must call this method after its value gets changed. – Alexandre Borela Jul 27 '15 at 12:49
  • For example, the BytesSent property, if you change the Set to call NotifyPropertyChange after _bytesSent= value, it will notify the UI the BytesSent was changed. – Alexandre Borela Jul 27 '15 at 12:52
  • So just to be sure: i will declare NotifyPropertyChange where i am changing the propertied inside the derive class ? – berry wer Jul 27 '15 at 13:04
  • I wrote an example, but yeah, every time you want to notify a change, you have to raise the event PropertyChanged inside the Set of the property, you don't need to reimplement the NotifyPropertyChange, that's why people normally create a method to do that, it simplifies. – Alexandre Borela Jul 27 '15 at 13:11
0

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()); }
}
Wulfy
  • 1
  • 1