Web Things Considered

Wednesday, September 14, 2005

DropDownList inside a GridView (or DataGrid)

I'm still coming up to full speed on ASP.NET, as evidenced by a conversation I had yesterday about Grids and DropDownLists and their events. In the interest of reinforcing the concepts, I've implemented a sample page and am summarizing it here to further commit it into my brain.

The page requirements:
1) Table/Grid displays a list of states (U.S. states) with a column for the state name and a column that contains a dropdown list of the state's cities.
2) Upon selecting a city, the page will display the city name (and perhaps futher lookup some information specific to the city).

The basic ASP.NET flow here is (using 2.0 here, but works similarly in 1.1 using DataGrid):
1) Create a GridView with a bound column for state and a template column for the DropDownList
2) Create a label to display the city name upon selecting it in the DropDownList.
3) Bind the GridView to an array of state objects (could be bound to many other things as well, but keeping it simple for this example). State contains properties for Name and for Cities.
4) Hookup RowCreated event on the GridView so that we can populate the cities into the particular row's DropDownList.
5) Add postback event for getting the selected city and populating the label with it.

Here's what the aspx code looks like:

<asp:GridView ID="gvStates" AutoGenerateColumns="false"
runat="server" OnRowCreated="gvStates_RowCreated">
<Columns>
<asp:BoundField HeaderText="State" DataField="Name" />
<asp:TemplateField HeaderText="Cities">
<ItemTemplate>
<asp:DropDownList ID="ddlCities"
AutoPostBack="true" runat="server"
OnSelectedIndexChanged="ddlCities_SelectedIndexChanged">
</asp:DropDownList>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>

<asp:Label ID="lblCity" runat="server" Text="Label">
</
asp:Label>

And here's the code behind:

protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
// Create states array and bind it to Grid
ArrayList states = new ArrayList();

string[] cities =
new string[] { "Portland", "Salem", "Eugene" };
State state = new State("OR", cities);
states.Add(state);
cities =
new string[] { "Seattle", "Tacoma", "Olympia" };
state = new State("WA", cities);
states.Add(state);

this.gvStates.DataSource = states;
this.gvStates.DataBind();
}
}

protected void gvStates_RowCreated(object sender,
GridViewRowEventArgs e)
{
if (!IsPostBack)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
// Bind drop down to cities
DropDownList ddl =
(DropDownList)e.Row.FindControl("ddlCities");
ddl.DataSource = ((State)e.Row.DataItem).Cities;
ddl.DataBind();
}
}
}

protected void ddlCities_SelectedIndexChanged(object sender,
EventArgs e)
{
this.lblCity.Text = ((DropDownList)sender).SelectedValue;
}


This code should be more defensive with null checking, type checking and exception handling in place. But, you get the idea of the general work flow (and now, so do I).

A couple of points that I'd like to highlight:
- AutoPostBack is required on the DropDownList in order to submit the page immediatlely opon selecting an item. For some reason I thought if the event was there, that was all that was needed (time to come out of my WinForms haze).
- Use the FindControl() method to grab a reference to the DropDown.
- In this case RowCreated or RowDataBound would work for binding the DropDownList. If you needed the State name to lookup cities, you would need to use RowDataBound. However in this case, since the object we're bound to already has the cities, RowCreated works fine too.

126 Comments:

Post a Comment

<< Home