Website development and design blog, tutorials and inspiration

Binding an ASP.Net Control to a Generic List

Generic Lists to ASP.Net Data Controls.

By , 21st February 2012 in C#

.Net makes it very easy to bind its own 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 exactly the same as the .Net native data structures.

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.

  1. List<string> colours = new List<string>();
  2. colours.Add("Black");
  3. colours.Add("Slate Gray");
  4. colours.Add("Midnight Blue");
  5. colours.Add("Steel Blue");
  6. colours.Add("Firebrick");
  7. colours.Add("Purple");
  8. colours.Add("Cyan");
  9. colours.Add("Sea Green");
  10. colours.Add("Dark Green");
  11. colours.Add("Yellow");
  12. colours.Add("Khaki");
  13. colours.Add("Dark Orange");
  14. 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:

  1. foreach (string colour in colours)
  2. 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.

  1. lstColours.DataSource = colours;
  2. 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.

List of colours
List of colours

Let us recreate the colours data list using a Dictionary using the HTML hex colour codes as the key.

  1. Dictionary<string, string> colours = new Dictionary<string, string>();
  2. colours.Add("#000000", "Black");
  3. colours.Add("#657383", "Slate Gray");
  4. colours.Add("#151B54", "Midnight Blue");
  5. colours.Add("#4863A0", "Steel Blue");
  6. colours.Add("#800517", "Firebrick");
  7. colours.Add("#8E35EF", "Purple");
  8. colours.Add("#00FFFF", "Cyan");
  9. colours.Add("#4E8975", "Sea Green");
  10. colours.Add("#254117", "Dark Green");
  11. colours.Add("#FFFF00", "Yellow");
  12. colours.Add("#ADA96E", "Khaki");
  13. colours.Add("#F88017", "Dark Orange");
  14. colours.Add("#FF0000", "Red");

This time when we bind the list to a control, we get 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.

Colour list with HEX values
Colour list with HEX values
  1. lstColours.DataSource = colours;
  2. lstColours.DataValueField = "Key";
  3. lstColours.DataTextField = "Value";
  4. 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.

Data Binding 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.

  1.  
  2. // The class we are going to use in this example
  3. public class Customer
  4. {
  5. private string _accountNumber;
  6. public string AccountNumber
  7. {
  8. get { return _accountNumber; }
  9. set { _accountNumber = value; }
  10. }
  11.  
  12. private string _name;
  13. public string Name
  14. {
  15. get { return _name; }
  16. set { _name = value; }
  17. }
  18.  
  19. private string _address;
  20. public string Address
  21. {
  22. get { return _address; }
  23. set { _address = value; }
  24. }
  25.  
  26. public Customer(string account, string name, string address)
  27. {
  28. _accountNumber = account;
  29. _name = name;
  30. _address = address;
  31. }
  32.  
  33. public override string ToString()
  34. {
  35. return string.Format("{0} ({1})", Name, AccountNumber);
  36. }
  37. }

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.

  1. lstCustomers.DataSource = customers;
  2. 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.

Binding a class to a list
Binding a class to a list
  1. lstCustomers.DataSource = customers;
  2. lstCustomers.DataValueField = "AccountNumber";
  3. lstCustomers.DataTextField = "Name";
  4. 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.

  1. protected void ListBox_OnClick(object sender, EventArgs e)
  2. {
  3. ListBox lb = sender as ListBox;
  4.  
  5. if (lb != null)
  6. {
  7. foreach (ListItem item in lb.Items)
  8. {
  9. object o = lb.DataSource;
  10. List<Customer> data = o as List<Customer>;
  11.  
  12. // Now get the customer selected
  13. Customer cust = data.Find(toFind => toFind.AccountNumber == item.Value);
  14.  
  15. // ...
  16. }
  17. }
  18. }

And that's how to bind generics to data controls!

Further Reading
Comments
  1. Simon Brown
    Simon Brown

    I found this as was interested in getting to the complex data associated with datasource property.
    I have a Datalist (rather than Listbox) control and bind the datasource to my own class as a list
    That all shows fine with my added checkbox to select multiple items.

    However when processing the Datalist from a submit button the datalist.datasource is set to null viewing from VS debugger.

    I would absolutely like to grab the matching entry in the datasource list for the complex class to process the request.
    Do you know why a datalist would not support this, I am using so can use templates to present multiple fields

Leave a Reply

Your email address will not be published.