Properties with property changed event

I often coach or teach .NET developers, and I’m often surprised how some folks write the most complex programs and discuss amazing architectures, but can’t get the basics right. So I’m planning to write a series of posts on .NET basics. I’ll use C# as a language, but most topics will be equally applicable to Managed C++ or Visual Basic.NET.

In this first post, I want to talk about simple properties with a changed event, as you will often find them on classes used in Windows Forms data binding scenarios. Take as an example a “Name” property of type string. We’ll use a backing field called “name”. In VB you can’t rely on casing to differentiate between the field and the property, so you’d probably call the field “nameValue” or something. The getter will simply return the field, but the setter needs to raise the event in addition to setting the field.

According to .NET standards, the event will be of type EventHandler and be called NameChanged. Any other type or name, and Winforms data binding will not work.

Many people write something along the lines of

private string name;

public string Name
{
    get { return name; }
    set    
    {        
        name = value;
        if (NameChanged != null)
        {
            NameChanged(this, e);
        }
    }
}

public event EventHandler NameChanged;

But that has approach has two problems associated with it. The first one is the easiest to understand: the NameChanged event will be raised, even if the Name didn’t really change. Let’s say the value of Name is null and I write

Name = null;

That will raise the event, even though nothing changed. That could result in wasted processing or worse. In the case where two such properties are bound to each other via their events, any assignment to either of them would cause an infinite recursion and a stack overflow. So you need to test if the value really changed before raising the NameChanged event.

The second problem has to do with inheritance. If your class might be used as a base class for derived classes, you need to give those derived classes an easy and efficient mechanism to react to a property change. Raising an event and then subscribing to that event yourself doesn’t count as efficient. So what we do instead is create a protected virtual method that raises the event. This allows derived classes to override the method to be notified of property changes. Simple, clean and efficient. According to .NET standards, we’ll call the method OnNameChanged. Event raising methods like this one have a single parameter of type EventArgs (or, in the general case, a class derived from EventArgs). That yields the following implementation:

private string name;

public string Name
{
    get { return name; }
    set
    {
        if (value != name)
        {
            name = value;
            OnNameChanged(EventArgs.Empty);
        }
    }
}

public event EventHandler NameChanged;

protected virtual void OnNameChanged(EventArgs e)
{
    if (NameChanged != null)
    {
        NameChanged(this, e);
    }
}

You can of course extend this basic pattern. For example you could make the property virtual as well, although that would slow it down considerably. Anyway, the pattern as above is quite a bit of typing as it is, and will cover most cases.

In part 2 of this series, where we talk about an alternative approach: using the INotifyPropertyChanged interface.

About these ads

8 Responses to “Properties with property changed event”


  1. 1 Mathi February 21, 2008 at 7:49 am

    Hello Kris,
    I am new to dot net.When I googled for propertychanged , I got your article, which was easy to me to understand.Thank You.
    When I tried to implement this, I am not able get the concept.The sample code that I have tried is :

    private string namevalue;
    public event EventHandler NamevalueChanged;
    public string Namevalue
    {
    get { return namevalue; }
    set {
    if (namevalue!=value )
    {
    namevalue = value;
    OnNamevalueChanged(EventArgs.Empty);
    }
    }
    }
    protected virtual void OnNamevalueChanged(EventArgs e)
    {

    /* Here the problem is :
    NamevalueChanged is always null and
    NamevalueChanged(this,e) not fired ever.is this nature..?
    */
    if (NamevalueChanged != null)
    NamevalueChanged(this, e);
    }

    I assigned the property by
    NameValue= txtName.Text;

    I am not able understand what is happening in this code and how do I know where the name value change.Please help me to understand the concept.Thank you again.

    With Regards,
    Mathi

  2. 2 Kris Vandermotten February 22, 2008 at 6:04 pm

    Mathi,

    Your code is correct, in the sense that your code now offers the event for other code to use. If nobody subscribes to the event, nobody will be notified.

    Assuming you have this in a class called X, try this:

    X x = new X();
    // this is where you subscribe:
    x.NamevalueChanged += delegate(object sender, EventArgs e)
    {
    Console.WriteLine(“Namevalue changed to ” + sender.Namevalue);
    };
    x.Namevalue = “Kris Vandermotten”;

    This is just an example, you’ll have to read more to understand the concept of delegates and events. I suggest you search MSDN for “event”, “delegate” and/or “EventHandler”.

    Kris.

  3. 3 Joe June 18, 2008 at 5:06 pm

    In this example the sender will always be the class with the property. Is there an elegant way to figure out WHO changed the property and make them the sender?

  4. 4 Kris Vandermotten June 18, 2008 at 6:56 pm

    Joe,

    Short answer: no.

    First of all, you would need to define “who”. Would that be the user running the code that modified the property? Or maybe the MethodInfo representing the method that called the property setter? Or something else?

    Once you have answered that, you need to find out how you are going to get that information. And believe me, you don’t want to abuse VB’s parameterized properties to do so.

    Last but not least, doing so would mean you modify the semantics of the event pattern, something you don’t want to do. They’re there for a reason. Furthermore, when developers handle an event, they expect the sender to represent the object that changed. Don’t let them down.

    The reason the sender is there, is to find out which object changed. Take a form with five textboxes, and handle the TextChanged event for all of them with one single method. The sender tells you which textbox changed. As another example, take a collection of products. When the price of a product changes, you need to recalculate total order prices. To speed up the calculation, you only recalculate those orders that actually contain the modified product. How do you know which product changed? The sender tells you.

    Hope this clarifies things.

    Kris.

  5. 5 Cleyton September 1, 2008 at 8:19 pm

    Hi

    Thanks for this interesting article.

    I am trying to improve my OO skills and as everyone else I am using a bank Account class to learn some OO concepts such as encapsulation, usability etc…

    This is my problem:

    1- I would like to create an event to indicate changes in the Balance property (read-only property) instead of using the DisplayBalance method after each button to deposit or withdraw money.

    private decimal _balance;

    public decimal Balance
    {
    get { return _balance; }
    }

    Call the DisplayBalance() method in the form:

    DisplayBalance()
    private void DisplayBalance()
    {
    balanceValueLabel.Text = _account.Balance.ToString(“C”);
    }

    However, your tutorial shows how to set an event to a setter not a getter property. How can I do the same thing using the get property?

    Cheers

    C

  6. 6 Kris Vandermotten September 4, 2008 at 6:54 pm

    Cleyton,

    Surely somewhere you set the _balance field, otherwise the Balance would never change and the event would be useless. So wherever it you set that field, that’s where you should call OnBalanceChanged.

    The easiest way to do that, especially if you set the field in multiple places, is to introduce a private setter:

    public decimal Balance
    {
    get { return _balance; }
    private set
    {
    if (value != _balance)
    {
    _balance = value;
    OnBalanceChanged(EventArgs.Empty);
    }
    }
    }

    In your code, set Balance instead of _balance and you’re done.

    Kris.

  7. 7 horsedrowner December 3, 2008 at 4:23 pm

    Hey,

    I suppose there is no .NET built in way to do this? This just seemes a standard operation, but I couldn’t find it yet. So far I’ll just have to use this :)

    Ruben

  8. 8 Julio December 4, 2013 at 6:56 am

    Hi Kris great post one thing that I still have issue to digest is using your original sample; let’s say I have a collections of Names and this collections is bind to a grid (windows forms) If I change the Name of one of the objects in the collections how can I notify the grid with the change.

    Do I need to create my own collection class which will force the rebind of the grid? or is any other better and efficient way to do this.

    Basically I want do to this:

    public class xEmail:: INotifyPropertyChanged
    {
    private string _subject;
    private string _emailId;
    private string _body;
    private string _owId;
    private List _toAddresses;
    private List _fromAddresses;
    private bool _isBeingProcessed;
    private bool _processed;

    public event PropertyChangedEventHandler PropertyChanged;

    public string Subject
    {
    get { return _subject; }
    set
    {
    _subject = value;
    OnPropertyChanged(“Subject”);
    }
    }

    public string EmailId
    {
    get { return _emailId; }
    set
    {
    _emailId = value;
    OnPropertyChanged(“EmailId”);
    }
    }

    public List ToAddresses { get; set; }
    public List FromAddresses { get; set; }
    public string Body
    {
    get { return _body; }
    set
    {
    _body = value;
    OnPropertyChanged(“Body1″);
    }
    }
    public bool Processed
    {
    get { return _processed; }
    set
    {
    _processed = value;
    OnPropertyChanged(“Processed”);
    }
    }
    public bool BeingProcessed
    {
    get { return _isBeingProcessed; }
    set
    {
    _isBeingProcessed = value;
    OnPropertyChanged(“BeingProcessed”);
    }
    }

    protected void OnPropertyChanged(string name)
    {
    if (PropertyChanged != null)
    {
    PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
    }
    }
    }

    Now i will have a grid in a windows form that will display a List and what i am trying to do is that when one of the objects in that collection updates one of the properties such as Subject that change gets reflected on the grid.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s





Follow

Get every new post delivered to your Inbox.

%d bloggers like this: