Click here to Skip to main content
Click here to Skip to main content

Bind Better with INotifyPropertyChanged

, 5 Oct 2006 CPOL
Rate this:
Please Sign up or sign in to vote.
Data bind using INotifyPropertyChanged
Sample Image - DemoGUI.jpg

Introduction

Data binding is a fantastic feature of many components in the development world. The ability to connect the value of a property on a data object to some other property on another component can save a lot of time and code, if it works. .NET 2.0 brings many new features to the table and has cleaned up some old features. The INotifyPropertyChanged is a powerful new interface in the System.Component namespace.

The INotifyPropertyChanged interface provides a standard way to notify binding clients of a property value change. In the past, it was sometimes hit-or-miss as to when or whether a binding client would recognize a property change on a data object. If developers did not know how to bend the data bound client to their will, then a lot of nasty code often followed, along with some very foul words about hating data binding. Implementing INotifyPropertyChanged will help you keep your code clean and get the most out of the hard work that other developers have done to implement binding clients.

Special thanks to Jason Wergin for the base class code, and for pointing out this new and very useful interface.

A Quick Look at INotifyPropertyChanged

The interface itself, like most elegant solutions, is disgustingly simple. It has no properties and no methods. It has just one event, with a simple and perfectly clear name, PropertyChanged. The delegate for this event has two parameters. The first, of course, is the sender, and the second, the PropertyChangedEventArgs, which has one property, PropertyName. As I said, “Simple”.

A Simple Base Class

Indeed the interface is so simple that you could write a very useful base class to speed the implementation of this interface across any data objects you would like to bind. Below is a simple base class that we use in some of the products that I am working on.

public abstract class NotifyProperyChangedBase : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
        #region methods
        protected bool CheckPropertyChanged<T>
		(string propertyName, ref T oldValue, ref T newValue)
        {
            if (oldValue == null && newValue == null)
            {
                return false;
            }

            if ((oldValue == null && newValue != null) || !oldValue.Equals((T)newValue))
            {
                oldValue = newValue;
                FirePropertyChanged(propertyName);              
                return true;                
            }

            return false;
        }

        protected void FirePropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
    }

The class wraps the logic to see if a value is changing in a generic method, and also provides a standard method call for raising the PopertyChanged event, all very simple and very useful. Now implementing the INotifyPropertyChanged interface is as simple as inheriting this base class and calling these two methods when needed.

Now Let’s See an Example

In this example, we are going to create two data objects, one that implements INotifyPropertyChanged and one that does not. Then we will bind instances of them to list boxes and see how differently they behave (see download for demo code).

  1. Open up Visual Studio 2005 and create a new C# Windows Forms project and name it INotifyDemo.
  2. In the same solution, create a new C# class library project and name it MyComponentModel. This project just represents the framework library that we should put our useful NotifyProperyChangedBase class in.
  3. Now add a new class to the MyComponentModel project and name it NotifyProperyChangedBase. The base class code laid out in the previous section of this article should be copied into the class file and saved.
  4. Right click on the MyComponentModel project in the solution explorer and click the Build menu item to compile the project.

Now we are going to create the two data objects. These are going to be simple person objects, one will use our new base class thereby implementing INotifyPropertyChanged, and the other will be a plain old regular object.

Add a new class to the INotifyDemo project and name it RegularPerson. Put the following code in the class:

class RegularPerson
    {
        private string _firstName;

        public string FirstName
        {
            get { return _firstName; }
            set { _firstName = value; }
        }

        private string _lastName;

        public string LastName
        {
            get { return _lastName; }
            set { _lastName = value; }
        }

        public string DisplayName
        {
            get { return _firstName + " " + _lastName; }
        }
    }

As you can see, it is a very vanilla data class that holds the name of a person.

Now we need to create a similar class that inherits our useful base class which implements the INotifyPropertyChanged interface. So, add another new class to the INotifyDemo project and name it NotifiablePerson. Put the following code in the class:

class NotifiablePerson : MyComponentModel.NotifyProperyChangedBase
    {
        private string _firstName;

        public string FirstName
        {
            get { return _firstName; }
            set 
            {
                if (this.CheckPropertyChanged<string>
			("FirstName", ref _firstName, ref value))
                {
                    this.DisplayNameChanged();
                }
            }
        }

        private string _lastName;

        public string LastName
        {
            get { return _lastName; }
            set 
            {
                if (this.CheckPropertyChanged<string>
			("LastName", ref _lastName, ref value))
                {
                    this.DisplayNameChanged();
                }
            }
        }

        public string DisplayName
        {
            get { return _firstName + " " + _lastName; }
        }

        private void DisplayNameChanged()
        {
            this.FirePropertyChanged("DisplayName");
        }
    }

In this class, we inherit the NotifyPropertyChangedBase class. In the setters for the FirstName and LastName properties, we use the generic CheckPropertyChanged method to set the class attribute that holds the property value and we raise the PropertyChanged event if needed. Also, if the property value indeed changes, then the read only property DisplayName also changes. So, we use the FirePropertyChanged method to inform the binding client of the change. Simple enough.

Now drag two groupboxes, two listboxes, and four textboxes onto Form1 and arrange them so the form looks like this:

With the form laid out, you need to wire up event handlers for the form Load event and for the TextChanged event on each of the text boxes. For each of the listboxes, set the DisplayMemeber property to DisplayName and the ValueMemeber property to FirstName. Now add code to Form1 until it looks like this:

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            LoadRegularList();

            LoadNotiList();            
        }

        private void LoadRegularList()
        {
            System.ComponentModel.BindingList<RegularPerson> rl = 
			new System.ComponentModel.BindingList<RegularPerson>();

            RegularPerson rp = rl.AddNew();
            rp.FirstName = "John";
            rp.LastName = "Smith";

            RegularPerson rp2 = rl.AddNew();
            rp2.FirstName = "Joe";
            rp2.LastName = "Shmoe";

            listBox1.DataSource = rl;
        }

        private void LoadNotiList()
        {
            System.ComponentModel.BindingList<NotifiablePerson> nl = 
			new System.ComponentModel.BindingList<NotifiablePerson>();
            
            NotifiablePerson np = nl.AddNew();
            np.FirstName = "Jane";
            np.LastName = "Doe";

            NotifiablePerson np2 = nl.AddNew();
            np2.FirstName = "Mary";
            np2.LastName = "Smith";

            listBox2.DataSource = nl;
        }

        private void textBox1_TextChanged(object sender, EventArgs e)
        {
            if (listBox1.SelectedItem != null)
            {
                ((RegularPerson)listBox1.SelectedItem).FirstName = textBox1.Text;
            }
        }

        private void textBox2_TextChanged(object sender, EventArgs e)
        {
            if (listBox1.SelectedItem != null)
            {
                ((RegularPerson)listBox1.SelectedItem).LastName = textBox2.Text;
            }
        }

        private void textBox3_TextChanged(object sender, EventArgs e)
        {
            if (listBox2.SelectedItem != null)
            {
                ((NotifiablePerson)listBox2.SelectedItem).FirstName = textBox3.Text;
            }
        }

        private void textBox4_TextChanged(object sender, EventArgs e)
        {
            if (listBox2.SelectedItem != null)
            {
                ((NotifiablePerson)listBox2.SelectedItem).LastName = textBox4.Text;
            }
        }
    }

On this form, we now have two lists whose item values we can manipulate. The top section edits the FirstName and LastName of the selected RegularPerson item in the list and the bottom section edits the same properties of the selected NotifiablePerson item in its list.

Build and run INotifyDemo.

Try selecting an item in the “Regular Person” list and typing a new name into either the “First Name” or “Last Name” text boxes. You will notice that the item text in the list does not change even though the underlying value has changed. You can set a break point on one of the TextChanged events and see that the value has indeed changed.

Now select an item in the “Notifiable Person” list and type a new name into either the “First Name” or “Last Name” text boxes. TA-DA! The item text in the list changes immediately. The binding client, in this case the list box, was informed via the PropertyChanged event and did its job perfectly; no need to write ugly code to get the listbox item text to refresh.

Conclusion

You can expect this kind of good behavior from all binding clients when you implement INotifyPropertyChanged. Create a good solid base class (like the one in this article) that implements the interface and use it on any object you wish to bind. It will allow you to take full advantage of binding clients and save you from having to write unnecessary and ugly code.

NOTE: We also used the generic BindingList; this is also recommended when binding collections to clients.

History

  • 5th October, 2006: Initial post

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

pconverse

United States United States
No Biography provided

Comments and Discussions

 
GeneralSimplier Version PinmemberMetalKid00719-May-10 5:17 
GeneralRe: Simplier Version Pinmemberke4vtw28-Jun-11 7:05 
GeneralRe: Simplier Version Pinmembervahapdemir10-Jan-12 6:12 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141220.1 | Last Updated 5 Oct 2006
Article Copyright 2006 by pconverse
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid