Microsoft Communities

Welcome to WindowsClient.net | Sign in | Join

Here are some frequently asked questions about Windows Forms and their answers.

Windows Forms FAQs

What is a BindingSource and why do I need it?

The BindingSource component provides a layer of indirection between the underlying data source and the bound UI controls.  The usage pattern for BindingSource is for it to be bound to the data source and for the UI controls to be bound to the BindingSource.  By sitting between the data source and controls, the BindingSource can provide services on behalf of the data source.  The most important services provided by the BindingSource are:

IBindingList services for non-IBindingLists including IEnumerable binding

Windows Forms complex data binding in VS 2005 will work correctly against lists of type IEnumerable when bound through a BindingSource (V1.0 and V1.1 required IList).  The BindingSource up-converts all non IBindingList based data sources to IBindingLists.  In the case of IEnumerable, the BindingSource will copy all data source elements into an internal list and indirectly binding controls to the internal list.

_bs = new BindingSource();

// Open SQLConnection
conn.Open();

// Get Reader
SqlDataReader reader = cmd.ExecuteReader();

// Binding IEnumerable
_bs.DataSource = reader;

// Close connection
conn.Close();

// Close connection
this.businessDataGridView.DataSource = _bs;

The IBindingList interface's AddNew() method is called by Controls to add new items to the bound list.  There may be times, such as when binding to a list of factory objects, where the list may not be able to create a new instance for the list.  In these cases, you can use the extensible AddNew capabilities of the BindingSource to provide your own implementation for AddNew().

public void Initialize()
{
  _bs = new BindingSource();

  // Add Customers
  _bs.Add(new Customer("555"));

  // Binding Simple Control
  this.lastNameTextBox.DataBindings.Add("Text", _bs, "LastName", true);

  // Binding Simple Control
  _bs.AddingNew += new AddingNewEventHandler(BindingSource_AddingNewEventHandler);

  // Bind to the BindingSource (supported at design time)
  this.customersDataGridView.DataSource = _bs;
}

private void BindingSource_AddingNewEventHandler(object sender, AddingNewEventArgs e)
{
  // Set new item
  e.NewObject = _service.CreateNewCustomer();
}

Supports type based binding (required for binding to factory based types)

The Windows Forms V1.0 and V1.0 designer required an instance of a type to exist at design time in order to setup design time data binding.  The BindingSource provides type binding services such that it can "project" a type to bound controls as an empty list of that type.  This enables both design time and runtime binding to factory based business objects:

public void Initialize()
{
  // Design time setup
  _bs = new BindingSource();

  // Design time (or run-time binding to type)
  // Controls bound to the BindingSource will act as if they are bound to an empty
  // typed list of Customers
  _dc.DataSource = typeof(Customer);
}

Provides centralized control for binding operations

A common binding request is the ability to suspend and resume binding for a data source.  In V1 and V1.1 the CurrencyManager provided SuspendBinding() and ResumeBinding() methods but these only worked for Simple Binding.  When binding through a BindingSource, you can suspend both simple and complex binding by having the BindingSource disable firing of ListChanged events (ListChanged events control binding).  To do this, set the BindingSource "RaiseListChangedEvents" property to false.

Simplifies currency management

The BindingSource component exposes most of the CurrencyManager events and properties (see the Currency Management section for more information on CurrencyManagers).  This enables design time event wire-up of common currency related events such as "CurrentChanged" and "PositionChanged".

Simplifies binding to web services via indirection

In V1 and V1.1, when binding to objects such as a DataSet, customers bind directly to the object (as is expected):

// DataSet is a member variable (_ds)

Services.BooksService   service = new Services.BookService();

_ds = service.GetBooksByAuthor(this.AuthorTextBox.Text);

// Bind Grid (show returned results)
this.authorsDataGridView.DataSource = _ds;

// Show details in simple controls
this.priceLabel.DataBindings.Add("Text", _ds, "Price");
this.publishDateLabel.DataBindings.Add("Text", _ds, "PublishDate");
this.ISBNLabel.DataBindings.Add("Text", _ds, "ISBN");

This works well for simple cases but can be problematic if the source object changes.  As a first attempt, many users try to re-set the bound object (see below).

// First attempt, reset the DataSet

_ds = service.GetBooksByAuthor(this.AuthorTextBox.Text);
Given this doesn't work, users move on re-setting all bindings:
public void AuthorSelected()
{
  DataSet ds = service.GetBooksByAuthor(this.AuthorTextBox.Text);

  // Reset All Bindings
  ResetBindings(ds);
}

public void ResetBindings(DataSet ds)
{
  // Bind Grid (show returned results)
  this.authorsDataGridView.DataSource = ds;

  // Show details in simple controls
  this.priceLabel.DataBindings.Add("Text", ds, "Price");
  this.publishDateLabel.DataBindings.Add("Text", ds, "PublishDate");
  this.ISBNLabel.DataBindings.Add("Text", ds, "ISBN");

}

While this does work, it requires more work on the user's part and cannot be setup at design time.  For DataSets, users can short circuit this, but few customers discover this:

// First attempt, reset the DataSet
DataSet ds = service.GetBooksByAuthor(this.AuthorTextBox.Text);

_ds.Clear();
_ds.Merge(ds);

The BindingSource provides a level of indirection at both design-time and run-time that alleviates the need for users to reset their bindings or merge data sets.

private BindingSource          _bs;

private void Initialize()
{
  _bs = new BindingSource();

  // Bind to the BindingSource (supported at design time)
  this.authorsDataGridView.DataSource = _bs;

  // Bind to the BindingSource (supported at design time)
  this.priceLabel.DataBindings.Add("Text", _bs, "Price");
  this.publishDateLabel.DataBindings.Add("Text", _bs, "PublishDate");
  this.ISBNLabel.DataBindings.Add("Text", _bs, "ISBN");
}

public void AuthorSelected()
{
  // Reset the BindingSource data source (resets bindings)
  _dc.DataSource = service.GetBooksByAuthor(this.AuthorTextBox.Text);
}    


Page view counter