DekGenius.com
[ Team LiB ] Previous Section Next Section

10.2 Simple and Complex Binding

The examples we have seen so far all use the technique known as simple binding. Simple binding has two defining characteristics:

  • Bindings deal with single pieces of information, both in the sense that single source properties are bound to single control properties, and also in the sense that only a single item from a list can be shown at any one time.

  • Simple binding requires no special support from the control—the data-binding architecture is able to bind to any control property, including any new properties you introduce in your custom controls.

Complex binding overcomes the restrictions of simple binding—it can allow a single control to display multiple entries from a list, and multiple properties from any single item. However, it requires special support from the control—most of the built-in controls do not support complex binding, and if you want your own controls to support it, you will need to do most of the work yourself. But don't be put off by the name—complex binding is only complex for the developer who creates the control; it can actually make things much simpler for developers who use the control.

The built-in controls that support complex binding are ListBox, ComboBox, and DataGrid. The first two work the same and we will start by looking at those. The DataGrid control's data-binding support is rather more extensive, and we will examine it later.

10.2.1 List Control Binding

The ListBox and ComboBox controls have a great deal in common. They share the same base class, ListControl, and this common base supplies their complex data-binding support. Both of these controls are able to bind to a list data source (such as an array) and display the entire contents of the list rather than just a single item.

Figure 10-1 shows a simple Windows Forms program.

Figure 10-1. Binding a ListBox to an array
figs/winf_1001.gif

The program in Figure 10-1 has three controls all bound to the same data source, which is an array of the MySource class defined earlier in C# in Example 10-4 and in VB in Example 10-5. The two TextBox controls on the right have been bound to this data source using simple binding, using exactly the same code as Example 10-9. This program has simply added one more control to Example 10-9, a ListBox. It is bound to the data source with the C# code shown in Example 10-15; the VB code is identical, except that it lacks the closing semicolon.

Example 10-15. Binding a ListBox to an array with complex binding
listBox.DataSource = myDataListSource;
listBox.DisplayMember = "Name";

Notice that we are no longer using the DataBindings property to bind the control to the data source, because DataBindings only supports simple binding. Instead, we are using the DataSource property, which is only present on controls that support complex binding. By setting this property to refer to the array, we are telling the ListBox that we would like it to display the whole array and not just the current entry of the array.

The ListBox control needs to know how it should display the items. By default, it will simply call the ToString method on every item in the list to which it is bound. This would not be helpful in this example because our MySource class does not override ToString, the default behavior of which is to return the name of the class. A ListBox in which every entry was the class name would not be very useful, so here we have instructed the ListBox to extract each item's Name property and display that. We achieved this by setting the ListBox control's DisplayMember property.

Notice that in Figure 10-1 the text fields are displaying the properties for the selected item in the listbox. This happens automatically because all three controls are bound to the same data source. Remember that the data-binding framework creates one binding manager for each data source in use on a form, and any control that is bound to that source is associated with that binding manager, whether it is using simple or complex binding. In this case, the data source is an array, so the binding manager will be a CurrencyManager. This CurrencyManager is responsible for keeping track of which list item is the current one. Whenever the listbox's current selection is changed, it notifies the CurrencyManager for the data source, thus causing any other controls that are bound to the same data source to reflect the newly selected list item. This notification works in both directions, so if something else were to change the current item, the CurrencyManager would notify all bound controls, causing the listbox to change the selected item. (For example, if you were to bind two listboxes to the same source, both would always show the same selected item, as long as both controls share the same BindingContext.)

There is a slight problem with the previous example. If you edit the text in the name field, the change is not reflected in the listbox. While the change is made to the underlying data, it is simply not noticed by the listbox, despite the fact that our MySource class now raises property change notifications. The problem arises because all controls that support complex data binding expect data sources that change their contents to implement a special interface derived from IList called IBindingList. The array class does not implement this interface, and it is not trivial to implement. However, there are some specialized data source classes that we will now look at that support IBindingList. Using these instead of a simple array can solve this problem.

    [ Team LiB ] Previous Section Next Section