Customizing GridView Control For Data Modifications

Introduction

This article is intended to illustrate how to customize GridView controls for data modification. We're going to change the standard BoundFields and CheckBoxFields (that don't offer customization features) for alternative extensible Web controls. We're going to walk through a common business scenario where we want to display a list of products using a GridView control, and allow the user to change the associated product subcategory rendered by a DropDownList control and using TemplateField techniques.

Developing the solution

To illustrate this data presentation technique, we will use the tables Production.Product (representing the business entity Product) and Production.ProductSubcategory (representing the subcategories associated with the products) in the database AdventureWorks shipped with SQL Server 2005. In our solution, we will display a list of the master data (data from the Production.ProductSubcategory) in a DropDownList Web control and inside a GridView control that displays a list of products.

The first step is to create a Web application by opening Visual Studio.NET 2005 and select "File" | "New" | "Web Site" as the front-end project. Let's create a Class Library project for the data access layer components. This separation of objects (concerning their responsibilities) follows the best practices of enterprise applications development.

Let's add a strongly typed DataSet item to the Class Library project (see Figure 1).

1.gif
 

Figure 1

Let's define a TableAdapter item representing the logic to access the Production.Product table in the database AdventureWorks using a SQL statement (see Figure 2).

2.gif
 

Figure 2

Let's also define a TableAdapter item representing the logic to access the Production.ProductSubcategory table in the database AdventureWorks by using a SQL statement (see Figure 3).

3.gif

Figure 3

We need to add an UPDATE SQL statement to the product table adapter in order to update the underlying product subcategory (see Figure 4).

4.gif
 

Figure 4

The result schema for the data access objects is shown in Figure 5.

5.gif
 

Figure 5

Now let's go to the Web front-end project and add a reference to the data access project (the Class Library project created before) and then add a Web form to the project named CustomizingGridView.aspx.

Now let's drag and drop a GridView control from the Toolbox onto the Web form, and set the ID property to gvProducts.

Next drag and drop an ObjectDataSource from the Toolbox onto the Web form, set the ID property to odtProducts, click on the smart tag and select the Configure Data Source option to launch the data source configuration wizard. In the first page ("Choose a Business Object") you must select the ProductTableAdapter (see Figure 6).

6.gif
 

Figure 6

Click on the "Next" button and in the Define Data Methods page, we select the "GetData" method (see Figure 7).

7.gif
 

Figure 7

Go to the "Update" tab and select the UpdateProductSubcategory method created before (see Figure 8).

8.gif
 

Figure 8

Click on the "Finish" button to finish the wizard. Go to the Property windows, and set the OldValuesParametersFormatString to {0}. Now let's bind the gvProducts GridView control to the odsProducts ObjectDataSource by clicking on the smart tag on the dgProducts GridView control and selecting the Choose Data Source option and setting the fields in the wizard. You must enable paging and editing features (see Figure 9).

9.gif
 

Figure 9

If you go to the code generated for the ObjectDataSource, you can see that the "Update" method expects two parameters, one is the product identifier and the other is the product subcategory identifier (see Listing 1).

<asp:ObjectDataSource ID="odtProducts" runat="server" DeleteMethod="Delete" SelectMethod="GetData"

    TypeName="ASPNETDatabindingDACPkg.DSProductionTableAdapters.ProductTableAdapter"

    UpdateMethod="UpdateProductSubcategory">

    <DeleteParameters>

        <asp:Parameter Name="Original_ProductID" Type="Int32" />

        <asp:Parameter Name="Original_Name" Type="String" />

        <asp:Parameter Name="Original_ProductNumber" Type="String" />

        <asp:Parameter Name="Original_ProductSubcategoryID" Type="Int32" />

    </DeleteParameters>

    <UpdateParameters>

        <asp:Parameter Name="ProductSubcategoryID" Type="Int32" />

        <asp:Parameter Name="ProductID" Type="Int32" />

    </UpdateParameters>

</asp:ObjectDataSource>

Listing 1

So, we need to set the ReadOnly property to True for all the columns in the GridView except the ProductSubcategoryID by clicking on the smart tag of the GridView control and the selecting Edit Columns option (for the case of the ProductNumber column see Figure 10).

10.gif
 

Figure 10

Now you can update the product subcategory identifier value using a TextBox control. The drawback with this solution is that you need to remember the map from the product subcategory name and its identifier. The solution is to provide a DropDownList control with the list of product subcategory name and enable the user to choose one from the list (not having to remember every name in the list).

To provide this behavior, we need to convert the ProductSubcategoryID  BoundField into a TemplateFields. Go to the GridView control's smart tag and click on it, then select the Edit Columsn option. In the Field windows, go to the ProductSubcategoryID in the Selected Fields list and click on the "Convert this field into a TemplateField" link on the lower right side. This conversion will create a TemplateField with an ItemTemplate and an EditTemplate (see Listing 2).

<asp:TemplateField HeaderText="ProductSubcategoryID" SortExpression="ProductSubcategoryID">

    <EditItemTemplate>

        <asp:TextBox ID="TextBox1" runat="server" Text='<%# Bind("ProductSubcategoryID") %>'></asp:TextBox>

    </EditItemTemplate>

    <ItemTemplate>

        <asp:Label ID="Label1" runat="server" Text='<%# Bind("ProductSubcategoryID") %>'></asp:Label>

    </ItemTemplate>

</asp:TemplateField>

Listing 2

In order to the change TextBox control for a DropDownList control, you need to go the GridView control's smart tag, click on it and select the Edit Templates option. Then choose to work with the EditTemplate of the ProductSubcategoryID field (see Figure 11).

11.gif
 

Figure 11

Delete the TextBox control and drag and drop a DropDownList control from the Toolbox onto the EditTemplate (see Figure 12).

12.gif
 

Figure 12

Then click on the DropDownList control's smart tag and select Edit DataBindings option and set the Field Binding of the SelectedValue bindable property to ProductSubcategoryID (see Figure 13).

13.gif
 

Figure 13

Now we need to define a data source to fill in the DropDownList with the list of names of subcategories and the underlying identifier. Click on the DropDownList control's smart tag and select the Choose Data Source option. In the Data Source Configuration Wizard, click on the "Select a data source" list and select the option "<New data source>" (see Figure 14).

14.gif
 

Figure 14

When the wizard is launched, in the first page, you select the type of data source (Object in this case) and the name (see Figure 15).

15.gif
 

Figure 15

Click the "OK" button and go to the "Choose a Business Object" page and select "ProductSubcategoryTableAdapter" (see Figure 16).

16.gif
 

Figure 16

Click on the "Next" button and go to the "Define Data Methods" page and in the "Select" tab, you need to choose the "GetData" option (see Figure 17).

17.gif
 

Figure 17

Finally, click on the "Finish" button. After the wizard is closed, we have returned to the Data Source Configuration Wizard for the DropDownList control. Then select the Name field as the display field and the ProductSubcategoryID as the value field (see Figure 18).

18.gif
 

Figure 18

In order to deal with the NULL supported by ProductSubCategoryID field (depending on the underlying data schema) and actually the DropDownList control does not include a list item for NULL, you need to manually add another list item for the NULL whose value is associated with an empty string that is automatically converted to NULL and vice-a-versa in ASP.NET 2.0. As well as, you need to set the "AppendDataBoundItems" property to True.

Go to the source and navigate to the DropDownList control inside the EditItemTemplate node, and add the AppendDataBoundItems="True" attribute as well as the ListItem element whose Value property is set to an empty string (see Listing 3).

<EditItemTemplate>

    &nbsp;<asp:DropDownList ID="DropDownList1" runat="server" DataSourceID="odsProductSubcategory"

        DataTextField="Name" DataValueField="ProductSubcategoryID" SelectedValue='<%# Bind("ProductSubcategoryID") %>' AppendDataBoundItems="True">

        <asp:ListItem Value="">(No value)</asp:ListItem>

    </asp:DropDownList><asp:ObjectDataSource ID="odsProductSubcategory" runat="server" OldValuesParameterFormatString="{0}" SelectMethod="GetData"

        TypeName="ASPNETDatabindingDACPkg.DSProductionTableAdapters.ProductSubcategoryTableAdapter">

    </asp:ObjectDataSource>

</EditItemTemplate>

Listing 3

Now, click on the GridView control's smart tag and click on the "End Template Editing" option (see Figure 19).

19.gif
 

Figure 19

Repeat the same steps for the ItemTemplate for the ProductSubcategoryID field, although you need to set the "Enable" property to False, because ItemTemplate represents the values in report mode for the GridView control, not in the updatable mode.

Conclusion

In this article, I've explained the main techniques to customize the GridView control using its TemplateFields features in ASP.NET 2.0.