WEBSITE

ASP.NET 4 in VB 2010 : The Data Controls - Using GridView Templates

6/5/2013 7:09:02 PM

So far, the examples have used the GridView control to show data using separate bound columns for each field. If you want to place multiple values in the same cell, or you want the unlimited ability to customize the content in a cell by adding HTML tags and server controls, you need to use a TemplateField.

The TemplateField allows you to define a completely customized template for a column. Inside the template you can add control tags, arbitrary HTML elements, and data binding expressions. You have complete freedom to arrange everything the way you want.

For example, imagine you want to create a column that combines the in stock, on order, and reorder level information for a product. To accomplish this trick, you can construct an ItemTemplate like this:

<asp:TemplateField HeaderText="Status">
  <ItemTemplate>
    <b>In Stock:</b>
    <%# Eval("UnitsInStock") %><br />
    <b>On Order:</b>
    <%# Eval("UnitsOnOrder") %><br />
    <b>Reorder:</b>
    <%# Eval("ReorderLevel") %>
  </ItemTemplate>
</asp:TemplateField>

NOTE

Your template only has access to the fields that are in the bound data object. So if you want to show the UnitsInStock, UnitsOnOrder, and ReorderLevel fields, you need to make sure the SqlDataSource query returns this information.

To create the data binding expressions, the template uses the Eval() method, which is a shared method of the System.Web.UI.DataBinder class. Eval() is an indispensable convenience—it automatically retrieves the data item that's bound to the current row, uses reflection to find the matching field, and retrieves the value.

The Eval() method also adds the extremely useful ability to format data fields on the fly. To use this feature, you must call the overloaded version of the Eval() method that accepts an additional format string parameter. Here's an example:

<%# Eval("BirthDate", "{0:MM/dd/yy}") %>


You'll notice that this example template includes three data binding expressions. These expressions get the actual information from the current row. The rest of the content in the template defines static text, tags, and controls.

You also need to make sure the data source provides these three pieces of information. If you attempt to bind a field that isn't present in your result set, you'll receive a runtime error. If you retrieve additional fields that are never bound to any template, no problem will occur.

Here's the revised data source with these fields:

<asp:SqlDataSource ID="sourceProducts" runat="server"
  ConnectionString="<%$ ConnectionStrings:Northwind %>"
  SelectCommand="SELECT ProductID, ProductName, UnitPrice, UnitsInStock,
UnitsOnOrder,ReorderLevel FROM Products"
  UpdateCommand="UPDATE Products SET ProductName=@ProductName,
UnitPrice=@UnitPrice WHERE ProductID=@ProductID">
</asp:SqlDataSource>

When you bind the GridView, it fetches the data from the data source and walks through the collection of items. It processes the ItemTemplate for each item, evaluates the data binding expressions, and adds the rendered HTML to the table. You're free to mix template columns with other column types. Figure 1 shows an example with several normal columns and the template column at the end.

Figure 1. A GridView with a template column

1. Using Multiple Templates

The previous example uses a single template to configure the appearance of data items. However, the ItemTemplate isn't the only template that the TemplateField provides. In fact, the TemplateField allows you to configure various aspects of its appearance with a number of templates. Inside every template column, you can use the templates listed in Table 1.

Table 1. TemplateField Templates
ModeDescription
HeaderTemplateDetermines the appearance and content of the header cell.
FooterTemplateDetermines the appearance and content of the footer cell (if you set ShowFooter to True).
ItemTemplateDetermines the appearance and content of each data cell.
AlternatingItemTemplateDetermines the appearance and content of even-numbered rows. For example, if you set the AlternatingItemTemplate to have a shaded background color, the GridView applies this shading to every second row.
EditItemTemplateDetermines the appearance and controls used in edit mode.
InsertItemTemplateDetermines the appearance and controls used in edit mode. The GridView doesn't support this template, but the DetailsView and FormView controls do.

Of the templates listed in Table 2, the EditItemTemplate is one of the most useful, because it gives you the ability to control the editing experience for the field. If you don't use template fields, you're limited to ordinary text boxes, and you won't have any validation. The GridView also defines two templates you can use outside any column. These are the PagerTemplate, which lets you customize the appearance of pager controls, and the EmptyDataTemplate, which lets you set the content that should appear if the GridView is bound to an empty data object.

2. Editing Templates in Visual Studio

Visual Studio includes solid support for editing templates in the web page designer. To try this, follow these steps:

  1. Create a GridView with at least one template column.

  2. Select the GridView, and click Edit Templates in the smart tag. This switches the GridView into template edit mode.

  3. In the smart tag, use the Display drop-down list to choose the template you want to edit (see Figure 2). You can choose either of the two templates that apply to the whole GridView (EmptyDataTemplate or PagerTemplate), or you can choose a specific template for one of the template columns.

    Figure 2. Editing a template in Visual Studio
  4. Enter your content in the control. You can enter static content, drag and drop controls, and so on.

  5. When you're finished, choose End Template Editing from the smart tag.

3. Handling Events in a Template

In some cases, you might need to handle events that are raised by the controls you add to a template column. For example, imagine you want to add a clickable image link by adding an ImageButton control. This is easy enough to accomplish:

<asp:TemplateField HeaderText="Status">
  <ItemTemplate>
    <asp:ImageButton ID="ImageButton1" runat="server"
     ImageUrl="statuspic.gif" />
  </ItemTemplate>
</asp:TemplateField>

The problem is that if you add a control to a template, the GridView creates multiple copies of that control, one for each data item. When the ImageButton is clicked, you need a way to determine which image was clicked and to which row it belongs.

The way to resolve this problem is to use an event from the GridView, not the contained button. The GridView.RowCommand event serves this purpose, because it fires whenever any button is clicked in any template. This process, where a control event in a template is turned into an event in the containing control, is called event bubbling.

Of course, you still need a way to pass information to the RowCommand event to identify the row where the action took place. The secret lies in two string properties that all button controls provide: CommandName and CommandArgument. CommandName sets a descriptive name you can use to distinguish clicks on your ImageButton from clicks on other button controls in the GridView. The CommandArgument supplies a piece of row-specific data you can use to identify the row that was clicked. You can supply this information using a data binding expression.

Here's a template field that contains the revised ImageButton tag:

<asp:TemplateField HeaderText="Status">
  <ItemTemplate>
    <asp:ImageButton ID="ImageButton1" runat="server"
     ImageUrl="statuspic.gif"
     CommandName="StatusClick" CommandArgument='<%# Eval("ProductID") %>' />
  </ItemTemplate>
</asp:TemplateField>

					  

And here's the code you need in order to respond when an ImageButton is clicked:

Protected Sub GridView1_RowCommand(ByVal sender As Object, _
  ByVal e As GridViewCommandEventArgs) Handles GridView1.RowCommand

    If e.CommandName = "StatusClick" Then
      lblInfo.Text = "You clicked product #" & e.CommandArgument.ToString()
    End If
End Sub

This example displays a simple message with the ProductID in a label.

4. Editing with a Template

One of the best reasons to use a template is to provide a better editing experienceYou saw how the GridView provides automatic editing capabilities—all you need to do is switch a row into edit mode by setting the GridView.EditIndex property. The easiest way to make this possible is to add a CommandField column with the ShowEditButton set to True. Then, the user simply needs to click a link in the appropriate row to begin editing it. At this point, every label in every column is replaced by a text box (unless the field is read-only).

The standard editing support has several limitations:


It's not always appropriate to edit values using a text box:

Certain types of data are best handled with other controls (such as drop-down lists). Large fields need multiline text boxes, and so on.


You get no validation:

It would be nice to restrict the editing possibilities so that currency figures can't be entered as negative numbers, for example. You can do that by adding validator controls to an EditItemTemplate.


The visual appearance is often ugly:

A row of text boxes across a grid takes up too much space and rarely seems professional.

In a template column, you don't have these issues. Instead, you explicitly define the edit controls and their layout using the EditItemTemplate. This can be a somewhat laborious process.

Here's the template column used earlier for stock information with an editing template:

<asp:TemplateField HeaderText="Status">
  <ItemStyle Width="100px" />
  <ItemTemplate>
      <b>In Stock:</b> <%# Eval("UnitsInStock") %><br />
      <b>On Order:</b> <%# Eval("UnitsOnOrder") %><br />
      <b>Reorder:</b> <%# Eval("ReorderLevel") %>
  </ItemTemplate>
  <EditItemTemplate>
    <b>In Stock:</b> <%# Eval("UnitsInStock") %><br />
    <b>On Order:</b> <%# Eval("UnitsOnOrder") %><br /><br />
    <b>Reorder:</b>
    <asp:TextBox Text='<%# Bind("ReorderLevel") %>' Width="25px"
     runat="server" id="txtReorder" />
  </EditItemTemplate>
</asp:TemplateField>

Figure 3 shows the row in edit mode.

Figure 3. Using an edit template

When binding an editable value to a control, you must use the Bind() method in your data binding expression instead of the ordinary Eval() method. Unlike the Eval() method, which can be placed anywhere in a page, the Bind() method must be used to set a control property. Only the Bind() method creates the two-way link, ensuring that updated values will be returned to the server.

One interesting detail here is that even though the item template shows three fields, the editing template allows only one of these to be changed. When the GridView commits an update, it will submit only the bound, editable parameters. In the previous example, this means the GridView will pass back a @ReorderLevel parameter but not a @UnitsInStock or @UnitsOnOrder parameter. This is important, because when you write your parameterized update command, it must use only the parameters you have available. Here's the modified SqlDataSource control with the correct command:

<asp:SqlDataSource ID="sourceProducts" runat="server"
  ConnectionString="<%$ ConnectionStrings:Northwind %>"
  SelectCommand="SELECT ProductID, ProductName, UnitPrice, UnitsInStock,
UnitsOnOrder,ReorderLevel FROM Products"
  UpdateCommand="UPDATE Products SET ProductName=@ProductName, UnitPrice=@UnitPrice,
ReorderLevel=@ReorderLevel WHERE ProductID=@ProductID">
</asp:SqlDataSource>

					  

4.1. Editing with Validation

Now that you have your template ready, why not add an extra frill, such as a validator, to catch editing mistakes? In the following example, a RangeValidator prevents changes that put the ReorderLevel at less than 0 or more than 100:

<asp:TemplateField HeaderText="Status">
  <ItemStyle Width="100px" />
    <ItemTemplate>
      <b>In Stock:</b> <%# Eval("UnitsInStock") %><br />
      <b>On Order:</b> <%# Eval("UnitsOnOrder") %><br />
      <b>Reorder:</b> <%# Eval("ReorderLevel") %>
    </ItemTemplate>
  <EditItemTemplate>
    <b>In Stock:</b> <%# Eval("UnitsInStock") %><br />
    <b>On Order:</b> <%# Eval("UnitsOnOrder") %><br /><br />
    <b>Reorder:</b>
    <asp:TextBox Text='<%# Bind("ReorderLevel") %>' Width="25px"
     runat="server" id="txtReorder" />
    <asp:RangeValidator id="rngValidator" MinimumValue="0" MaximumValue="100"
     ControlToValidate="txtReorder" runat="server"
     ErrorMessage="Value out of range." Type="Integer"/>
  </EditItemTemplate>
</asp:TemplateField>

					  

Figure 4 shows the validation at work. If the value isn't valid, the browser doesn't allow the page to be posted back, and no database code runs.

Figure 4. Creating an edit template with validation

NOTE

The SqlDataSource is intelligent enough to handle validation properly even if you disabled client-side validation (or the browser doesn't support it). In this situation, the page is posted back, but the SqlDataSource notices that it contains invalid data (by inspecting the Page.IsValid property), and doesn't attempt to perform its update. 

4.2. Editing Without a Command Column

So far, all the examples you've seen have used a CommandField that automatically generates edit controls. However, now that you've made the transition over to a template-based approach, it's worth considering how you can add your own edit controls.

It's actually quite easy. All you need to do is add a button control to the item template and set the CommandName to Edit. This automatically triggers the editing process, which fires the appropriate events and switches the row into edit mode.

<ItemTemplate>
  <b>In Stock:</b> <%# Eval("UnitsInStock") %><br />
  <b>On Order:</b> <%# Eval("UnitsOnOrder") %><br />
  <b>Reorder:</b> <%# Eval("ReorderLevel") %>
  <br /><br />
  <asp:LinkButton runat="server" Text="Edit"

CommandName="Edit" ID="LinkButton1" />
</ItemTemplate>

In the edit item template, you need two more buttons with CommandName values of Update and Cancel:

<EditItemTemplate>
  <b>In Stock:</b> <%# Eval("UnitsInStock") %><br />
  <b>On Order:</b> <%# Eval("UnitsOnOrder") %><br /><br />
  <b>Reorder:</b>
  <asp:TextBox Text='<%# Bind("ReorderLevel") %>' Width="25px"
   runat="server" id="txtReorder" />
  <br /><br />
  <asp:LinkButton runat="server" Text="Update"
   CommandName="Update" ID="LinkButton1" />
  <asp:LinkButton runat="server" Text="Cancel"
   CommandName="Cancel" ID="LinkButton2" CausesValidation="False" />
</EditItemTemplate>

Notice that the Cancel button must have its CausesValidation property set to False to bypass validation. That way, you can cancel the edit even if the current data isn't valid.

As long as you use these names, the GridView editing events will fire and the data source controls will react in the same way as if you were using the automatically generated editing controls. Figure 5 shows the custom edit buttons.

Figure 5. Custom edit controls
Other  
 
Most View
HTC Droid DNA Review (Part 1)
AMD A10-5800K - The First Chip In Processor Of New Trinity PC
Sony NEX-6 Mirrorless Camera Review (Part 13)
Windows Server 2008 R2 : Active Directory certificate services (part 2) - Deploying Active Directory Certificate Services
Smartphone Tips - Quick Advice For Simple Problems (Part 1)
How To Build A Better Mail Client
ASP.NET 4 in VB 2010 : Page Tracing (part 1) - Enabling Tracing, Tracing Information
New Gadgets For April 2013 (Part 1)
Windows 8 Explorer : Diagnosis and Recovery - The Performance and App History Tabs
VoltaBox - Superior Battery Pack Solutions (Part 1)
Popular Tags
Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Indesign Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe After Effects Adobe Photoshop Adobe Fireworks Adobe Flash Catalyst Corel Painter X CorelDRAW X5 CorelDraw 10 QuarkXPress 8 windows Phone 7 windows Phone 8 BlackBerry Android Ipad Iphone iOS
Top 10
Review : Acer Aspire R13
Review : Microsoft Lumia 535
Review : Olympus OM-D E-M5 Mark II
TomTom Runner + MultiSport Cardio
Timex Ironman Run Trainer 2.0
Suunto Ambit3 Peak Sapphire HR
Polar M400
Garmin Forerunner 920XT
Sharepoint 2013 : Content Model and Managed Metadata - Publishing, Un-publishing, and Republishing
Sharepoint 2013 : Content Model and Managed Metadata - Content Type Hubs