Thursday, March 31, 2011

What's the best way to call INotifyPropertyChanged's PropertyChanged event ?

When you implement the INotifyPropertyChanged interface, you're responsible for calling the PropertyChanged event each and everytime a property is updated in the class.

This typically leads to the following code :

    public class MyClass: INotifyPropertyChanged

        private bool myfield;
        public bool MyField
        {
            get { return myfield; }
            set
            {
                if (myfield == value)
                    return;
                myfield = value;
                OnPropertyChanged(new PropertyChangedEventArgs("MyField"));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            PropertyChangedEventHandler h = PropertyChanged;
            if (h != null)
                h(this, e);
        }
   }

That is 12 lines per property.

It would be so much simpler if one was able to decorate automatic properties like this :

[INotifyProperty]
public double MyField{ get; set; }

But unfortunately this is not possible (see this post on msdn for example)

How can I reduce the amount of code needed per property?

From stackoverflow
  • What I do for now is that I write this in my class :

     //AUTOGENERATE INotifyProperty
     private bool myfield;
    

    And I wrote a small tool which generate all the needed property code in a partial class. This is by no way an elegant solution, but it works :)

  • Actually, it's only 3-4 lines per property; the other lines are amortized over all "notifying" properties:

    class Person : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged: Shared bit
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, e);
        }
        #endregion
    
        private string _firstName;
        public string FirstName
        {
            get { return _firstName; }
            set
            {
                if (_firstName == value)
                    return;
                _firstName = value;
                OnPropertyChanged(new PropertyChangedEventArgs("FirstName"));
            }
        }
    
        // Ditto for other properties
    }
    

    You could try something like the following, which shares some more of the load:

    private string _firstName;
    public string FirstName
    {
        get { return _firstName; }
        set { SetNotifyingProperty("FirstName", ref _firstName, value); }
    }
    private void SetNotifyingProperty<T>(string propertyName,
                                         ref T field, T value)
    {
        if (value.Equals(field))
            return;
        field = value;
        OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }
    
    Brann : Good idea. Btw, another problem with that code is that a new instance of PropertyChangedEventArgs is created each and every time a property changes. EventArgs could be stored in members variable for later use.

0 comments:

Post a Comment