It's a common need in developing software to change control values based on data from a database or a property on an object. For example, choosing a customer name in a ListBox and filling in all their details into some form controls. You might first begin by implementing code in OnSelectedIndexChanged events, OnTextChanged events, etc.

Luckily, there's a very easy way to bind data to Windows Forms controls using a database, web service, or an actual object you've created. It's called the BindingSource control.

What is a BindingSource?

A BindingSource creates two-way databinding between some data source and a Windows Forms control. Data sources include a database, web services, or objects.

The easiest way to explain it is to give you some hands-on experience. In this tutorial I will have you build a simple UI and bind some data to it. We're going to build a simple application that will view and edit some customer data.

Download Source Code for this Tutorial (PDF of article included)

Building the UI

We're going to keep this short and simple. We want to be able to list some customers, edit their data, and manage their pet information.

Create a new C# Windows Application project and open up Form1.

First, let's add a ListBox control for listing customer names:

customerlistbox

Next, drag some labels and TextBox controls for the customers' Name, Email, and Phone Number. Position them however you want.

textandlabels

Drag a DataGridView to the form.

datagrid

All done! Our UI is complete for this tutorial. Let's move on to the fun part.

Creating Some Data

We are listing customers and their pets but because I don't want to have you create data in a database, we're going to create some classes with our data. I find it more cool to bind to actual objects and I think it's more helpful than going over database binding because typically you'd create entities like this anyway.

First, let's create our Customer class. Right-click your project, click Add –> Class… and name it Customer.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BindingSourceTutorial
{
    public class Customer
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public string PhoneNumber { get; set; }

        // My Pets
        public List<Pet> Pets { get; set; }

        protected Customer()
        {
            // force NewCustomer method
        }

        public static Customer NewCustomer(int id, string name, 
            string email, string phoneNumber)
        {
            Customer c = new Customer();
            c.ID = id;
            c.Name = name;
            c.Email = email;
            c.PhoneNumber = phoneNumber;
            c.Pets = new List<Pet>();

            return c;
        }
    }
}

Make sure to declare you classes public!

As you can probably see, we've created the customer's attributes (properties) and we've created a method called NewCustomer(...) that returns a new customer with our desired attributes. I added the ID property to hold a unique ID for a customer, it's not really needed for this tutorial. You may have also noticed I made the constructor protected. This is just a common pattern to use when creating "business objects," because sometimes you'd like to save this data to a file and load it, and when .NET loads data from a file it does not support constructor parameters (at least for XMLSerializer, but that's for another day).

Next, let's create our Pet class, name it Pet.cs.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BindingSourceTutorial
{
    public class Pet
    {
        public string Name { get; set; }
        public string Type { get; set; }
        public string Age { get; set; }

        protected Pet()
        {
            // force NewPet method
        }

        public static Pet NewPet(string name, string type, string age)
        {
            Pet p = new Pet();
            p.Name = name;
            p.Type = type;
            p.Age = age;

            return p;
        }
    }
}

We now have a Pet class that has a Name, Type, and Age. Customers have pets, so if you had a database this would be a many-to-one relationship. We will model that by going back to our Customer.cs file and adding a new property, underneath PhoneNumber:

// My Pets
public List<Pet> Pets { get; set; }

If you're not familiar with the generics, then the List<Pet> type might be confusing to you. Since .NET 2.0, we can create what's called a generic type. For example, instead of creating an array of Pets like public Pet[] PetsArray { get; set; } we create a List of type Pet. A List is a generic that has become a lot more powerful with the introduction of LINQ extension methods. Using a generic list exposes more functionality than an array would (like Where, Distinct, Any, All, etc) that almost make it as if you're using SQL to get the objects you want. If you're interested, read up on Generics and LINQ to Objects.

Now, we are finished with creating our data schema, so let's bind some data!

In order to browse the list of customers, we need a property that holds the list. To keep things simple, let's just add a property to our Form1.cs:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace BindingSourceTutorial
{
    public partial class Form1 : Form
    {

        public List<Customer> Customers { get; set; }

        public Form1()
        {
            InitializeComponent();
        }
    }
}

Binding the Interface

Let's set up our BindingSources now. Press Ctrl-Shift-B to build the project.

Click our Customers ListBox control and click the little arrow in the top right corner.

Click "Use data bound items." Click the "Data Source" drop-down and then the "Add Project Data Source…" link to start the new data source wizard.

listbox_datasource_1

Select "Object," click Next, then browse to: BindingSourceTutorial –> Form1. Click Finish.

listbox_form1

Notice how the designer has created a "form1BindingSource" control. However, we haven't chosen the Customers data source yet. Click "Data Source" again and expand the "form1BindingSource" and click "Customers." Now we've chosen the Customers data source and the designer has created an associated control, "customersBindingSource."

listbox_customers

So now click the "Display Member" drop down and choose "Name." This is the property that will be displayed in the ListBox control. Click the "Value Member" drop-down and choose "ID." This is the property that the ListBox item's value will be.

listbox_value_display

If you build and run the project now, nothing will show up in the Customer ListBox. That's what's supposed to happen, since we haven't created any data yet.

Now, let's bind the rest of the controls. For non-list style controls, you need to go into the Properties window and expand the "(Data Bindings)" attribute. For the TextBox controls, select the Text attribute and click the drop-down. Expand "customersBindingSource" and choose the appropriate attribute.

textbox_databinding

For the DataGridView, select it and click the white arrow in the top right corner. Select Data Source, expand "customersBindingSource," and select Pets.

datagrid_pets

Notice how the DataGridView automatically creates all the columns! Like always, the designer has created a "petsBindingSource." So cool.

Lastly, we want to be able to add and remove pets, so click the "petsBindingSource" and set the "AllowNew" property to true. Notice how the DataGridView automatically added a row to allow adding records.

pets_allownew

Hooking Everything Up

Now our BindingSources are created! Now all we need to do is simulate actual data by making some ourselves when the form loads up. Then we just assign the data sources!

Double-click your Form1 so we can create some data:

private void Form1_Load(object sender, EventArgs e)
{
    // Initialize
    Customers = new List<Customer>();

    // Create customers
    Customers.Add(Customer.NewCustomer(1, 
        "Bob the Builder", 
        "bob@buildings.com", 
        "123-456-9876"));
    Customers.Add(Customer.NewCustomer(2, 
        "Sara Cuttingham", 
        "ham@cutting.com", 
        "123-456-1234"));
    Customers.Add(Customer.NewCustomer(3, 
        "Tony Spumoni", 
        "tony@spumonis.com", 
        "234-543-8765"));
    Customers.Add(Customer.NewCustomer(4, 
        "Butch McBuffpants", 
        "bench274@bodybuilders.com", 
        "123-564-1276"));

    // Now create their pets!
    // Bob
    Customers[0].Pets.Add(Pet.NewPet("Fluffy", "Cat", 12));
    Customers[0].Pets.Add(Pet.NewPet("Ruffles", "Dog", 5));
    // Sara
    Customers[1].Pets.Add(Pet.NewPet("Charles", "Guinea Pig", 45));
    // Tony
    Customers[2].Pets.Add(Pet.NewPet("Sunshine", "Fish", 2));
    Customers[2].Pets.Add(Pet.NewPet("Rascal", "Fish", 1));
    Customers[2].Pets.Add(Pet.NewPet("Chainsaw", "Cat", 3));
    // Butch has no pets :(

    // Always cite your sources
    customersBindingSource.DataSource = Customers;
}

So, now we have our dataset! But why are we only binding one data source? That's because the rest of the controls on the page only use the customersBindingSource, so there's no need to bind anything else!

Cool Tips: Notice how we just bound the data source to the Customers List, just as it was created. What if we wanted to sort the data? Then we could do:

customersBindingSource.DataSource = Customers.OrderBy(c => c.Name);

What if we only wanted customers with pets?

customersBindingSource.DataSource = Customers.Where(c => c.Pets.Count > 0).ToList();

Cool, eh?

Press F5 and witness the magic. Try editing, add or removing pets, and selecting other customers. All your changes are saved.

There's an Even Faster Way!

Now I am going to blow your mind and you may hate me for it. Open up the Data Sources tab by clicking View –> Data Sources.

datasources

Expand the Form1 data source and click the Customers property. Click the drop-down arrow and select "Customize…" then choose ListBox in the checkbox list. You can click "Set Default" if you want.

customize_datasource

Now, click the drop-down again and select ListBox. Then drag the Customers property onto the form.

Magically, a binding source, a binding navigator, and a ListBox control are created.

bindingnavigator

To recreate our form, we don't need a binding navigator so you can just delete it.

Now just drag the rest of the properties of Customers from the Data Sources pane onto the form. Be sure to select DataGridView for the Pets property.

Run it and voila, all done! See, we didn't even have to manually associate all the controls! I know you may be angry, but I think it is better to show you the foundation so you understand the concepts before telling you how to make it easier.

Have fun and remember, always cite your sources!

Questions You May Have

Q. Can I bind two controls to the same exact BindingSource control?

A. Yes, but data will be reflected by both of them. This causes trouble when trying to bind two ListBox controls to one BindingSource.

Q. Can I have a list item's selected item be bound to a value?

A. Of course, just follow the same method as a TextBox control except bind the value to the SelectedValue property. If binding to a ComboBox that allows editing, I recommend binding to the Text property.