views:

99

answers:

1

I have some UI controls that are using DataBindings.Add method, and it works if I change the specified UI property by hand, or the source object is changed outside.

But if I invoke the UI.Property = value in code, then it doesn't change the UI nor the source object that's specified for DataBindings.Add.

What am I doing wrong? Am I using it incorrectly?

+3  A: 

The control won't know that anything has changed unless the object implements INotifyPropertyChanged. Then, the property setter in the object is changed to raise the PropertyChanged event, passing in the name of the property that changed in the event arguments.

INotifyPropertyChanged is a particular interface that the databinding mechanism in WinForms looks for when wiring up data binding. If it sees an object that implements that interface, it'll subscribe to its event, and you'll see your UI refreshed automatically without having to tell the databindings to re-read their values (which is what happens if you re-assign the DataSource, etc).

Not obvious, but it makes sense when you think about. Without an event being broadcast, how would the UI control know that the property has changed? It's not polling the property every so often. It has to get told that the property changed, and the PropertyChanged event is the conventional way to do that.

Something like (uncompiled code)...


public class MyInterestingObject : INotifyPropertyChanged
{
    private int myInterestingInt;

    public event PropertyChangedEventHandler PropertyChanged;

    public int MyInterestingInt
    {
       get { return this.myInterestingInt; }
       set
       {
           if (value != this.myInterestingInt)
           {
               this.myInterestingInt = value;
               this.RaisePropertyChanged("MyInterestingInt");
           }
       }
    }

    private void RaisePropertyChanged(string propertyName)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
        {
             handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

Now any code that has a databinding to that object's MyInterestingInt property will update itself when that property is changed. (Some people get fancy with proxies to implement this interface for them.)

A caveat: be sure that you set the updated value before you raise the PropertyChanged event! It's easy to do and can leave you scratching your head as to why the value isn't being updated.

Nicholas Piasecki
Thanks, I will search for articles for how to implement it.
Joan Venge
Sure, I added an example. MSDN also talks about it at http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx. Good luck.
Nicholas Piasecki
Thanks Nicholas. I have 2 questions: 1. PropertyChangedEventArgs can take any type? 2. This binding will also allow me to change the UI and have the object updated too, right?
Joan Venge
Actually I have 1 more question. After this all I need is to use DataBindings.Add, right? Because of the flaky updates that I experienced, I was using DataBindings.Clear and DataBindings.Add for each change.
Joan Venge
Yes, once you Add(), that's when it will subscribe to the PropertyChanged event and receive further updates. The UI will update the object as part of a two-way databinding. It's updating the UI after changing a property programmatically that INotifyPropertyChanged solves. Make sense?
Nicholas Piasecki
Thanks Nicholas, totally makes sense. I had 1 more question but forgot. Will ask you if I remember when I get home. Thanks again.
Joan Venge
Ok I just remembered it. When I need to assign another instance of MyInterestingObject to the filed/property that stores it, will it be automatically recognized by the DataBinding UI? And do I need to do additional work such as clearing the bindings and re-adding them?
Joan Venge
Let's you say you have a Form with a field named 'objectInstance', which is an instance of MyInterestingObject. You databind the MyInterestingInt property to some textbox, let's say, textbox.DataBindings.Add(new Binding("Text", this.objectInstance, "MyInterestingInt"). So if you do this.objectInstance.MyInterestingInt = 5, the textbox gets updated. But if you this.objectInstance = new MyInterestingObject(), the databinding is still pointing to the old reference. You need to clear and re-add the binding to listen to changes on the new object. (Pretty sure, it's late. :)
Nicholas Piasecki
Thanks that's what I was thinking.
Joan Venge
Also do you know the difference between DataBindings.Add ( new Binding ( string, object, string ) )... and DataBindings.Add ( string, object, string ) ?
Joan Venge
Actually I tried the new code, but no it doesn't work. The problem I have is the other way around. I change the UI in code, MyInterestingObject still prints the old values.
Joan Venge
One is just a shortcut that creates a Binding object for you. You need to use the overload that has the DataSourceUpdateMode parameter to make it a two-way binding. Using a BindingSource lets you do most of this at design time. Because this isn't the best forum for explanation, I've uploaded a small demo app to my Web site, which should make things make a lot more sense: http://piasecki.name/misc/BindingDemo.zip
Nicholas Piasecki