Tuesday 29 September 2009

Custom .Net Two Way Bindable Properties

Often when creating .Net applications that interface with a database a developer will want to create custom controls that bind in a similar way to database fields as the existing controls like TextBoxes and CheckBoxes.

Getting the control to update to reflect the database value is trivial. You can just add a DataBinding as you would with another control. But this will not propogate updates back to the data object. In order to do this you need to implement two way data binding on your custom control. Start by adding the attribute [Bindable(true)] to the property in question and then implement the INotifyPropertyChanged interface. An example of how to do this can be found on MSDN here: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx.

The catch comes if you ignore the advice to not implement INotifyPropertyChanged and provide an additional event for the property you want to bind to. If you call the additional event Property Name + "Changed" then the .Net framework binding code seems to get confused and the two way binding will not work. Eg if you property is called ClickCount and the additional event is called ClickCountChanged the two way binding will fail.

I was surprised by this as I have seen tutorials on two way data binding that encourage the provision of events for individual properties as well as the generic PropertyChanged event. Just remember that if you must do this be careful with the name of the events.

Here is a quick code sample that demonstrates how to create a control with two way binding:
  1 public class ButtonCounter : Button, INotifyPropertyChanged
2
{
3
private int clickCount;
4
5
public event PropertyChangedEventHandler PropertyChanged;
6
7
[Bindable(true)]
8
public int ClickCount
9
{
10
get
11
{
12
return clickCount;
13
}
14
set
15
{
16
if (value != clickCount)
17
{
18
clickCount = value;
19
Text = clickCount.ToString();
20
DoPropertyChanged("ClickCount");
21
}
22
}
23
}
24
25
public ButtonCounter()
26
{
27
Click += (o, e) =>
28
{
29
ClickCount += 1;
30
};
31
ClickCount = 0;
32
}
33
34
public void DoPropertyChanged(string propertyName)
35
{
36
if (PropertyChanged != null)
37
{
38
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
39
}
40
}
41
}

No comments:

Post a Comment