|
Setting the SelectedIndex Programmatically
Recently in a project I was working on I needed to be able to set the SelectedIndex of a DataList based on the values being
bound to the DataList. Specifically, I had a DataList that utilized a SelectedItemTemplate like so:
|
<%# DataBinder.Eval(Container.DataItem, "SomeField") %>
...
<%# DataBinder.Eval(Container.DataItem, "SomeOtherField") %>
...
|
The ItemTemplate and SelectedItemTemplate were much more involved than the simple versions shown above, and differed from one
another in a multitude of ways. When the page was visited, and the data was bound, I wanted a particular row made the selected row
based on the data in the row. Imagine that the data I'm binding to the DataList is information about products in my product
database. Perhaps passed in the QueryString to this page is a ProductID. I might want to make the item in the DataList that has the
corresponding ProductID selected. In a similar vein, perhaps I want to have the cheapest, or most expensive, or newest product selected
by default. How can I acheieve this functionality?
My first attempt was to create an event handler for the DataList's ItemDataBound event. Then, in this event handler I
checked to see if whatever condition I was checking for was met, and, if it was, I set the DataList's SelectedIndex
property to the ItemIndex of the item being processed. That is, my event handler looked like something like the following:
|
void myDataList_ItemDataBound(object sender, DataListItemEventArgs e)
{
// check to make sure we're dealing with an Item or AlternatingItem
if (e.Item.ItemType == ListItemType.Item ||
e.Item.ItemType == ListItemType.AlternatingItem)
{
// check to see if some condition is true
object di = e.Item.DataItem;
int productID = Convert.ToInt32(DataBinder.Eval(di, "ProductID"));
if (productID == Convert.ToInt32(Request.QueryString["ID"]))
{
// if the condition holds, set the DataList's SelectedIndex property
myDataList.SelectedIndex = e.Item.ItemIndex;
}
}
}
| | C# |
While this code successfully sets the DataList's SelectedIndex, the specified item is not rendered using the
SelectedItemTemplate. However, if the Web Form is posted back, by say a Button Web control click, then the item set in the
ItemDataBound event handler is rendered with the SelectedItemIndex. What's going on here?
The problem lies in the order with which various events transpire in the creation of the DataList.
Let's step through the series of events that transpire when the DataList's DataBind()
method is called. For each item in the DataList's DataSource, the following things happen in this order:
- A DataListItem instance is created.
- The proper template is used to render the contents of the DataListItem. It's at this point that the DataList's
SelectedIndex is checked to see whether the ItemTemplate should be used or if the SelectedItemTemplate should be
used.
- The DataList's
ItemCreated event is raised.
- The DataListItem's
DataItem property is set to the current DataSource row, and the
DataListItem's DataBind() method is called.
- The DataList's
ItemDataBound event is raised.
By examining the above sequence of events, it hopefully is evident why we can't simply set the SelectedIndex property in
the DataList's ItemDataBound event and have it work as planned. The reason is because the SelectedItemTemplate has already
been applied several steps before the DataList's ItemDataBound event fires. So, if setting the SelectedIndex
in the ItemDataBound event handler is too late, where can we set this property?
The answer is, before the DataList's DataBind() method is called! That is, we have to loop through the data that
will be bound to the DataList prior to binding it to the DataList to determine the index of the piece of data we want to have be the
selected index. Then, we need to set the DataList's SelectedIndex property to this discovered index value. Finally, we
call the DataList's DataBind() method. With this approach, everything will work as desired since we are setting the DataList's
SelectedIndex property before any of the steps outlined above transpire.
The following code demonstrates how to determine the index for the DataList's SelectedIndex property prior to binding
the data to the DataList.
|
// We need to use a DataTable (or DataSet) because we need to
// be able to loop through the records, searching for the record
// that is the "selected record". A DataReader only allows one-way,
// one-time forward access through the data, so DataReader's are not an
// option here...
// Create the connection and populate a DataTable
SqlConnection myConnection = new SqlConnection(CONNECTION_STRING);
SqlCommand myCommand = new SqlCommand(SQL_QUERY, myConnection);
SqlDataAdapter myAdapter = new SqlDataAdapter(myCommand)
DataTable dt = new DataTable();
myAdapter.Fill(dt);
// Now, search through the DataTable, looking for the index of the
// record that has the ProductID field equal to the ProductID
// specified in the QueryString...
for (int i = 0; i < dt.Rows.Count; i++)
{
if (Convert.ToInt32(dt.Rows[i]["ProductID"]) ==
Convert.ToInt32(Request.QueryString["ID"]))
{
// set the DataList's SelectedIndex property
myDataList.SelectedIndex = i;
break; // exit the for loop...
}
}
// Now, bind the DataTable to the DataList
myDataList.DataSource = dt;
myDataList.DataBind();
| | C# |
That's all there is to it! There's a live demo written in VB.NET that illustrates
how this technique can be used to select the record from the DataTable that has a column with the maximum value among all records in
the DataTable.
On a closing note, realize that the material in this FAQ focuses specifically on the DataList only, since the DataList is the
only data Web control with a SelectedItemTemplate. However, this functionality can be applied to the templates of the other data
Web controls in a similar fashion. Happy Programming!
|