Binding an ASP.Net Control to a Generic ListIn this tutorial I will show you how to bind ASP.Net Control to a Generic List or array of objects and control how they dispay.
.Net makes it very easy to bind its data objects to data controls, but there are times when you may wish to bind a generic, or even custom data structure, to a data control. This tutorial will show you how to bind a generic data object and a custom class to data-bound controls so that they behave the same as the .Net native data structures.
Binding ASP.Net Control to a Generic List
In this first example, I will show you how to bind a simple List object to a drop-down box. First, we need some data, so I'm going to create a static list of colours.
List<string> colours = new List<string>();
colours.Add("Black");
colours.Add("Slate Gray");
colours.Add("Midnight Blue");
colours.Add("Steel Blue");
colours.Add("Firebrick");
colours.Add("Purple");
colours.Add("Cyan");
colours.Add("Sea Green");
colours.Add("Dark Green");
colours.Add("Yellow");
colours.Add("Khaki");
colours.Add("Dark Orange");
colours.Add("Red");
Now, you may be tempted to loop through each item and add it to a list by creating a new list item:
foreach (string colour in colours)
lstColours.Items.Add(new ListItem(colour));
While this method will certainly get the job done, it is perhaps not the most efficient nor the correct way of doing things. Instead, you should bind the data to the list box, and that is done just like binding an ADO.Net DataSet.
lstColours.DataSource = colours; lstColours.DataBind();
This will produce a user-selectable list (ListBox, ComboBox, CheckListBox etc...) of colours where the key and the value are both set to the colour name. While this may be the result you need, more often than not you will need a separate value, or code, for each item which you can later use. In this instance, you will need to use a generic data type that supports a key/value pair such as a Dictionary or Hashtable.
Let us recreate the colours data list using a Dictionary using the HTML hex colour codes as the key.
Dictionary<string, string> colours = new Dictionary<string, string>();
colours.Add("#000000", "Black");
colours.Add("#657383", "Slate Gray");
colours.Add("#151B54", "Midnight Blue");
colours.Add("#4863A0", "Steel Blue");
colours.Add("#800517", "Firebrick");
colours.Add("#8E35EF", "Purple");
colours.Add("#00FFFF", "Cyan");
colours.Add("#4E8975", "Sea Green");
colours.Add("#254117", "Dark Green");
colours.Add("#FFFF00", "Yellow");
colours.Add("#ADA96E", "Khaki");
colours.Add("#F88017", "Dark Orange");
colours.Add("#FF0000", "Red");
This time when we bind the list to a control, we get a different and unexpected, result as shown in the image to the right. This is because the standard ToString() method of the Dictionary class will return both the key and the value together - not what we were looking to get!
What we need to do is tell the list box what to use as the key and what to use as the value. This is where it gets slightly confusing as the key of the colours object will become the value of the list item, and the value of the colours object will be the list item text.
lstColours.DataSource = colours;
lstColours.DataValueField = "Key";
lstColours.DataTextField = "Value";
lstColours.DataBind();
This will now result in a list that is shown like the first example, but the value of the selected item will be the hexadecimal colour code of the selected colour!
Remember: Unless you tell the list otherwise, it will use the default .ToString() method to set both the item value and item text. You must use DataValueField and DataTextField to tell it which fields to use.
Control Data Binding to a Class
This technique can also be used to bind a collection of classes to a list as well. For this, to work you need to specify the properties to be used as the key and value.
/ The class we are going to use in this example
public class Customer
{
private string _accountNumber;
public string AccountNumber
{
get { return _accountNumber; }
set { _accountNumber = value; }
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
private string _address;
public string Address
{
get { return _address; }
set { _address = value; }
}
public Customer(string account, string name, string address)
{
_accountNumber = account;
_name = name;
_address = address;
}
public override string ToString()
{
return string.Format("{0} ({1})", Name, AccountNumber);
}
}
This class defines three public properties, a constructor to make adding new items easier and an override for the ToString() method. Next, we populate a list of Customer classes.
List<Customer> customers = new List<Customer>();
customers.Add(new Customer("123456", "Bob Smith", "1 Some Street"));
customers.Add(new Customer("789012", "Jane Doe", "2 Example Road"));
customers.Add(new Customer("345678", "John Smith", "3 Sample Lane"));
customers.Add(new Customer("901234", "Jane Fonda", "4 Sample Avenue"));
Now we can bind this list to a list box control as we have done before.
lstCustomers.DataSource = customers; lstCustomers.DataBind();
As seen in the previous examples, this default binding will use the ToString() method of the List item object. This is shown in the image to the right which shows our overridden ToString() being used. As with the colours list, we can tell the list box which properties of the class to use for the key and the value.
lstCustomers.DataSource = customers;
lstCustomers.DataValueField = "AccountNumber";
lstCustomers.DataTextField = "Name";
lstCustomers.DataBind();
This will now bind the class property AccountNumber to the list item value property, and the Name property of the class to the list item text.
In your C# code behind, when the form is submitted you can retrieve the account number of the selected item from the list by accessing its SelectedItem property.
When binding complex data structures to ASP.Net controls, it is often helpful to access the full record, not just the value and description. In these instances, you can use the code below to get the full list item from a list box data source.
protected void ListBox_OnClick(object sender, EventArgs e)
{
ListBox lb = sender as ListBox;
if (lb != null)
{
foreach (ListItem item in lb.Items)
{
object o = lb.DataSource;
List<Customer> data = o as List<Customer>;
/ Now get the customer selected
Customer cust = data.Find(toFind => toFind.AccountNumber == item.Value);
/ ...
}
}
}
And that's how to bind generics to data controls!