In the previous GridView post, we figured out how to create a simple updating GridView without a lick of code. But it only updated a value from a TextBox, nothing too difficult about that. What would happen if one of the columns needed a DropDownList for editing purposes? This is something that required code in ASP.NET 1.1. The DropDownList needed to be bound in the ItemDataBound event, and that was only for display purposes. Updating required even more code. Can the declarative code model handle this twist without resulting to actual -- gasp -- coding?
I'll save the suspense and admit that, in fact, it is possible to create an Editable, Updating GridView with a DropDownList without writing any code. Here it is. We'll talk about the interesting bits afterwards.
<asp:GridView ID="GridViewDropDown" runat="server" DataSourceID="TestSqlSource" AutoGenerateEditButton="True" DataKeyNames="NameID" AutoGenerateColumns="False" >
<asp:BoundField HeaderText="Name" DataField="Name" />
<asp:TemplateField HeaderText="Popularity Trend">
<asp:DropDownList ID="PopularityTrendDropDown" runat="server" SelectedValue='<%# Bind("PopularityID") %>' DataSourceID="PopularitySqlSource" DataTextField="Description" DataValueField="PopularityID" ></asp:DropDownList>
<asp:Label ID="PopularityTrendLabel" runat="server" Text='<%# Eval("Description") %>'></asp:Label>
<asp:SqlDataSource ID="TestSqlSource" runat="server" ConnectionString="<%$ ConnectionStrings:TestConnectionString %>" SelectCommand="SELECT Name, NameID, PopularityID, Description FROM [BabyName] bn Left join Popularity p on bn.PopularityID = p.PopularityID" UpdateCommand="UPDATE BabyName SET Name = @Name, PopularityID = @PopularityID WHERE NameID = @NameID" >
<asp:SqlDataSource ID="PopularitySqlSource" runat="Server" ConnectionString="<%$ ConnectionStrings:TestConnectionString %>" SelectCommand="SELECT PopularityID, [Description] FROM [Popularity]" >
There are now 2 data sources, one for the GridView, and the PopularitySqlSource for the PopularityTrendDropDown. The PopularitySqlSource just provides a simple list of the possible values to display in the dropdown. TestSqlSource's SelectCommand has a new join and and an extra column, Description. This is so that the Item template can display the user friendly text value in the label. I was searching for a sexier way of doing this, so I didn't have to include the join and column in the statement, but heck, as long as we're polluting the aspx with SQL statements might as well use all the SQL we can.
In order to use a DropDown in the GridView, we need to stop autogenerating the columns and create a TemplateField for the column that has the DropDown. The TemplateField has two parts: the ItemTemplate and the EditItemTemplate. The ItemTemplate simply shows the user friendly description of the PopularityTrend. The EditItemTemplate holds the DropDownList for selecting the proper PopularityID. Whatever is in the EditItemTemplate is what shows up when the user clicks on the Edit button.
There is a little bit of data binding script syntax needed to properly bind the underlying values into the controls. For the DropDownList we bind the SelectedValue to the PopularityID...
SelectedValue='<%# Bind("PopularityID") %>'
The bit bewteen <%# and %> is actually a call to the Bind method which sets up the control to do two-way binding so that it can keep track of updates. This is used behind the scenes for the BoundField too. Technically this is coding, but since we are not creating a separate code file or breaking out the <script> tags, we'll ignore it.
Similarly the Text property of the label is bound using the Eval method.
Text='<%# Eval("Description") %>'
The difference between Eval and Bind, is that Eval is a read-only binding, it can't be used to update the underlying datasource.
So all that is needed to create a GridView that uses a DropDownList to edit a column value is:
- A TemplateField to hold the DropDown when a row is being edited, and a label when it is not
- A DataSource for the list portion of the DropDown control
- A little extra SQL to get the friendly description for the label
- A wee bit of binding
So, still no code, but our GridView and DataSource declarations are getting heftier. Probably still slimmer than the analogous code, but not nearly as compact as the simple GridView from the previous example.
Actually, if there were a DropDownField available the declarative syntax could be almost as slim as it was for the simple GridView. I'm surprised that there wasn't a DropDownField class created for ASP.NET 2.0 given their frequent use for editing grid columns. I'm sure someone has created one (or is is creating one) that could be added in. Could be a fun little project.
Next time, we'll see if we can add in multi-row editing without code. I have my doubts.