Team LiB
Previous Section Next Section

Data Binding Mechanics

So far all you've seen code for has been some very simple data binding. Before getting into more involved data binding code, you should know how the guts of the data binding system works. Three classes are present within Windows Forms data binding, whether you notice them or not. The main class responsible for all binding is BindingContext. This class can give you an instance of the CurrencyManager or the PropertyManager, depending on whether you are using simple binding (as in the example you saw earlier) or complex binding to a list-type data source.

The BindingContext Class

Every control on a form can have a single BindingContext instance associated with it. Each BindingContext class is the designated manager for a collection of BindingManagerBase objects (such as a CurrencyManager or a PropertyManager). The most common use of the BindingContext class is to obtain a Windows Form's current BindingContext to gain access to the binding managers for all the controls on that form.

If subsections of your form require independent data binding code, you can create a BindingContext for a container control such as a GroupBox or a Panel to provide a separate set of binding code for the grouped control.

The BindingContext class contains the expected methods for managing a collection, so you can add, remove, and clear the collection of BindingManagerBase classes. The most commonly used method is the indexer method, which enables you to access an individual BindingManagerBase class based on a data source object and the name of the binding (this is often the name of a table, DataRelation, or property). The indexer is two-dimensional. The first dimension is the data source for which you are trying to obtain a BindingManagerBase class. The second dimension is the name of the data member. As mentioned previously, this data member can be the name of a DataTable or the name of a property.

To illustrate how to obtain a BindingContext and use it to get a BindingManagerBase class, the following two lines are added to the beginning of the btnExamine_Click event handler from Listing 30.1:

BindingManagerBase bmLabel = BindingContext[ lblSimpleBinding, "Text" ];
MessageBox.Show(bmLabel.GetType().ToString());

When you run the new application, you'll see that the BindingManagerBase class for the lblSimpleBinding control is a RelatedPropertyManager class. Property managers will be discussed shortly.

The CurrencyManager Class

The CurrencyManager class is used to maintain the current position within the bound list for a given control. Obviously, you can't have the same position for each bound control, so each control bound to a list-type data source will have its own CurrencyManager that you can access via the BindingContext class. Table 30.1 provides a list of the public properties exposed by the CurrencyManager class.

Table 30.1. Public Properties Exposed by the CurrencyManager Class

Property

Description

Bindings

Contains the collection of bindings maintained by the CurrencyManager.

Count

Indicates the number of rows in the underlying data source.

Current

The current object. In a CurrencyManager, this is one element within the list-type data source.

List

Gets the list to which the CurrencyManager is bound.

Position

Indicates the current position within the list.


Additional control over your data binding code can be exerted through the various events that are published by the BindingManagerBase class and its descendants. Table 30.2 lists the events to which you can subscribe on the CurrencyManager class.

Table 30.2. Events of the CurrencyManager Class

Event

Description

CurrentChanged

This event is fired when the bound value changes.

ItemChanged

This event is fired when the current item changes.

MetaDataChanged

This event is fired when the metadata associated with the list changes.

PositionChanged

This event is fired when the current position changes. This should not be confused with events that indicate the bound data is changing.


Listing 30.2 illustrates a sample Windows Forms application that makes use of the currency manager. Although you could accomplish what this application does in other ways, it is extremely valuable and important for you to learn to work with the CurrencyManager if you will be writing any kind of complex, data-driven Windows Forms applications in the future.

Listing 30.2. A Sample Application That Illustrates the Use of the CurrencyManager Class and Complex Data Binding
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace CurrencyManager
{
  public class frmCurrencyManager : System.Windows.Forms.Form
  {
    private System.Windows.Forms.ListBox listBox1;
    private System.Windows.Forms.Label label1;
    private System.Windows.Forms.Label lblCurrentValue;
    private System.Windows.Forms.Label label2;
    private System.Windows.Forms.Label lblPosition;
    private ArrayList al;

    /// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.Container components = null;

    public frmCurrencyManager()
    {
      InitializeComponent();

      al = new ArrayList();
      al.Add( "Monday" );
      al.Add( "Tuesday" );
      al.Add( "Wednesday" );
      al.Add( "Thursday" );
      al.Add( "Friday" );
      al.Add( "Saturday" );
      al.Add( "Sunday" );

     listBox1.DataSource = al;

     System.Windows.Forms.CurrencyManager cm =
       (System.Windows.Forms.CurrencyManager)BindingContext[ al ];
     cm.CurrentChanged += new EventHandler(cm_CurrentChanged);
     cm_CurrentChanged(this, null);
    }

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    protected override void Dispose( bool disposing )
    {
      if( disposing )
      {
        if (components != null)
        {
          components.Dispose();
        }
      }
      base.Dispose( disposing );
    }

    // Windows Forms designer code edited out for clarity.

    [STAThread]
    static void Main()
    {
      Application.Run(new frmCurrencyManager());
    }

    private void cm_CurrentChanged(object sender, EventArgs e)
    {
      System.Windows.Forms.CurrencyManager cm =
        (System.Windows.Forms.CurrencyManager)BindingContext[ al ];
      lblCurrentValue.Text = cm.Current.ToString();
      lblPosition.Text = cm.Position.ToString();
    }
  }
}

Here a standard list box is bound to an ArrayList that represents the days of the week. At the end of the form's constructor, a reference to the CurrencyManager is obtained (note that you don't have to keep that reference in scope for all of this code to work because the form itself has the original references) and then an event handler for the CurrentChanged event is rigged up.

When this event is fired, the code updates a display that shows the current value and the current position of the binding context. Figure 30.2 shows how this application looks when running.

Figure 30.2. The CurrencyManager sample illustrating the use of a CurrencyManager class in binding.


The PropertyManager Class

The PropertyManager class is used when dealing with simple binding. When you create a simple binding via Bindings.Add, the resulting BindingManagerBase class is a PropertyManager. The properties in Table 30.3 apply to the PropertyManager class.

Table 30.3. Properties of the PropertyManager Class

Property

Description

Bindings

Contains the collection of bindings managed by this class.

Count

Gets the number of rows being managed by the class. For property managers, this is always 1.

Current

Gets the object to which the data-bound property has been associated.

Position

Gets the current position within the list-based data source. In a property manager, this is always 0.


    Team LiB
    Previous Section Next Section