ASP.NET & GridView

This article was originally published in VSJ, which is now part of Developer Fusion.
The latest ASP.NET control, GridView, is taking over from DataGrid in the next version of ASP.NET (code-named Whidbey). GridView preserves the DataGrid programming model as much as possible, although it is not 100% backward compatible.

However, moving grid-based code from ASP.NET 1.x pages is a relatively smooth and seamless operation – ranging from renaming fields to adjusting properties.

The new GridView control offers some improvements in functionality over DataGrid, such as the ability to define multiple primary key fields, new field types and template options, and offers a new model for developers to handle and cancel events.

In ASP.NET 2.0, both the DataGrid and GridView controls are available; they share similar goals but propound different object models. You should stick to DataGrid controls if you’re simply adapting your existing code to work on the new Web platform. You should be looking at the new GridView control in case of new applications or a full rewrite of existing code.

Should you rewrite much of your binding code only because the GridView control provides some user interface enhancements and a richer object model? Of course, not. There are other, and much more compelling, reasons to move from DataGrid and embrace the newest GridView control.

A new binding model

The killer feature of the GridView control is its full integration with the new ASP.NET 2.0 data source controls. In short, the GridView data-bound control accepts input from two types of data containers – enumerable objects and objects based on the new IDataSource interface.

In ASP.NET 1.x, data-bound controls can be associated with any managed object that exposes either the IEnumerable interface (e.g., arrays, collections, DataView) or IListSource (DataTable and DataSet). In ASP.NET 2.0, all data-bound controls can also be bound to data source controls, namely controls that implement the IDataSource interface. Data source controls are non-visual page components that return data of a given type. Table 1 details the principal data source controls.

Table 1: ASP.NET 2.0 Data Source Controls

Component Data Source and description
SqlDataSource Feeds data-bound controls with relational data (SQL Server, Oracle, DB2, …)
AccessDataSource Feeds data-bound controls with data taken out of Access databases
ObjectDataSource Enables business objects to associate their contents to data-bound controls
SiteMapDataSource Hierarchical component, represents the content of a site map
XmlDataSource Hierarchical component, represents any XML contents accessible through a file

At its core, a data source component represents one or more named views of data. Each view provides an enumerable collection of bindable objects – objects with public properties.

Each data source component – regardless of the physical data it contains – allows you to manage its own contents through SQL-like statements such as SELECT, INSERT, DELETE, and UPDATE. Let’s see an example.

<form runat=”server”>
	<asp:GridView runat=”server”
		id=”MyGridView”
		DataSourceID=”MySource” />
	<asp:SqlDataSource runat=”server”
		id=”MySource”
		ConnectionString=”...”
		SelectCommand=”select * from
		authors” />
</form>
In the preceding code snippet, the GridView control receives data to display from the bound data source – the MySource control. DataSourceID is a new property that is filled with the ID of the control providing display data. Whenever the GridView control needs binding to data, it calls a method on the associated data source. The method invoked varies with data source control of choice, but at the highest level of abstraction it maps to a basic operation like SELECT, INSERT, UPDATE, DELETE, COUNT. In the preceding code snippet, to get its display data the GridView invokes a method on the SqlDataSource class which ends up executing the command specified through the SelectCommand property. The invoked method is defined on the IDataSource interface.

As you can see, there’s no need for the page developer to write a single line of code. The GridView enables a completely declarative, property-driven syntax for common data scenarios, such as read-only and read/write tabular reports and master/details pages.

Interestingly, the old DataGrid control (as well as all ASP.NET 1.x data-bound controls) supports this same set of capabilities. The following code, in fact, works just fine.

<form runat=”server”>
	<asp:DataGrid runat=”server” id=”MyGrid”
		DataSourceID=”MySource” />
	<asp:SqlDataSource runat=”server” id=”MySource”
		ConnectionString=”...”
		SelectCommand=”SELECT * FROM authors” />
</form>
So where’s the key difference between DataGrid and GridView? It lies in read/write reporting scenarios.

Advanced binding capabilities

In Web applications, it is fairly common to use a grid to edit, sort, and delete data rows. With DataGrids, you are required to write custom code to handle operations such as paging, sorting, editing or deleting data. The DataGrid provides a skeleton of code but relies on the page developer to flesh it out with data access code. The GridView control can automatically handle these operations provided that the bound data source control supports these capabilities. As far as the SELECT operation is concerned, GridView and DataGrid have similar capabilities. If you move on to consider other scenarios (edit and delete), the superior design of the GridView clearly wins. The developer simply indicates the primary key field (or fields) for the data items, and sets boolean properties to indicate that the GridView should render edit and delete buttons; the GridView handles the rest. Here’s an example:
<form runat=”server”>
	<asp:GridView runat=”server” id=”MyGridView”
		DataSourceId=”MySource”
		AutoGenerateEditButton=”true”
		DataKeyNames=”au_id” />
	<asp:SqlDataSource runat=”server” id=”MySource”
		ConnectionString=”...”
		SelectCommand=”SELECT * FROM customers”
		UpdateCommand=”UPDATE customers
			SET companyname=@companyname,
			country=@country WHERE
			customerid=@original_customerid” />
</form>
Note that the UpdateCommand property, as well as SelectCommand and DeleteCommand, can be equally easily set to stored procedures names.

Figure 1 shows this code in action. Can you really say it’s a brand new control working from this picture?

Figure 1
Figure 1: The GridView control makes in-place editing really easy

What do you think will occur once a user clicks the Update link of the figure? If you are used to working with ASP.NET 1.x DataGrids, you might expect that some event handler is hidden somewhere in the page – perhaps auto-generated by Visual Studio .NET – to carry out the update through the specified command or stored procedure. Believe it or not, there’s no such code anywhere. The update occurs through the specified command, but no code apparently works it out. Is it pure magic? Quite the reverse.

The GridView is a pretty smart control that implements internally a good few event handlers to manage similar situations – updating or deleting a row or page; sorting the view or counting the bound records. Similar handlers exist in DataGrids, but they are limited to “bubbling” events up to the hosting page. In the GridView, handlers contain code to retrieve the bound data source control, locate the appropriate method, and execute it.

What about parameters? To perform an update, at the very minimum you need to indicate the unique ID of the row to update. How do you do that?

<asp:SqlDataSource runat=”server”
	ID=”MySource”
	ConnectionString=”...”
	SelectCommand=”SELECT * FROM
		customers
		WHERE country=@TheCountry”>
	<SelectParameters>
		<asp:QueryStringParameter
			Name=”TheCountry”
			QueryStringField=”Country”
			/>
		</SelectParameters>
</asp:SqlDataSource>
Each data source control method support a collection of parameters – SelectParameters in the code snippet above. Parameters can be expressed through the usual constant values or using values taken from a variety of sources – control properties, cookies, form fields. Table 2 shows the list of feasible parameters and their source.

Table 2: Supported Parameters

Parameter Description
ControlParameter Value from any public property of a control
CookieParameter
FormParameter Value from the specified input field in the form
ProfileParameter Value from the specified property name in the profile object created from web.config
QueryStringParameter Value from the specified variable in the request query string
SessionParameter Value based on the content of the specified Session slot

When you specify a QueryStringParameter, the value for the parameter is taken from the query string token that corresponds to the parameter name. In this way, you can declaratively bind command parameters with other dynamically created elements on and around the page.

Field types

As already mentioned, the GridView’s object model has many points of contact with the DataGrid’s object model. In both cases, you define a set of columns and the final output is made of a collection of rows. Object names have changed, though. What was a column within the DataGrid model becomes a field in the GridView jargon. Likewise, DataGrid items become GridView rows. The renaming applies to events, properties, and markup tags. To define a set of display columns for a GridView, you use the following code:
<columns>
	<asp:boundfield
		datafield=”customerid”
		headertext=”ID” />
	<asp:boundfield
		datafield=”companyname”
		headertext=”Company” />
</columns>
Despite the topmost container tag retaining the same name as with the DataGrid – Columns – individual columns are named as fields. Table 3 lists the available types of field. As you can see, the list is nearly identical to that of a DataGrid except the suffix of object names – “field” instead of “column”.

Table 3: Supported Columns

Type of column Description
BoundField Default column type. Displays the value of a field as plain text.
ButtonField Displays the value of a field as a command button. You can choose the link or the push button style. When clicked, the page posts back and fires a RowCommand server event.
CheckBoxField Displays the value of a field as a check box. It is commonly used to render Boolean values.
CommandField Enhanced version of ButtonField that represents special commands like Edit, Delete, Select.
HyperLinkField Displays the value of a field as a hyperlink. When you use this type, you normally bind one data field for the hyperlink’s text and one for the hyperlink’s URL. When the hyperlink is clicked, the browser navigates to the specified URL. Accepts an array of data fields to build multi-param URLs.
ImageField Displays the value of a field as an image. The image can come from a database or be specified through a URL.
TemplateField Displays user-defined content for each item in the column. Use this column type when you want to create a custom column field. The template can contain any number of data fields combined with literals, images, and other controls.

All classes in Table 3 derive from the base DataControlField class. These classes are used also by other view controls new to ASP.NET 2.0. These controls are DetailsView and FormView and are covered later in this article.

Each column type exposes a few properties to handle header and footer style and text, row style, sort expression. In addition to this common set of properties, each column type can add new and custom properties depending on its own role and expected behavior. Figure 2 shows a few of these columns in action.

Figure 2
Figure 2: The GridView control in action with different types of column

CheckBoxField, ImageField, and CommandField represent a step forward with respect to the programming model of DataGrids. These column objects save you from using templates to implement common pieces of user interface such as columns of checkboxes or images. The CommandField instead is an enhanced version of the ButtonField class specifically designed to handle system commands like Delete, Select, and Edit.

Templates

A TemplateField column gives each row in the grid a personalized user interface that is completely defined by the page developer. You can define templates for various rendering stages, including the default view, in-place editing, header, and footer. The supported templates are listed in Table 4.

Table 4: Supported Templates

Template Description
AlternatingItemTemplate Defines the contents and appearance of alternating rows. If not specified, the ItemTemplate is used.
EditItemTemplate Defines the contents and appearance of the row currently being edited. This template should contain input fields and possibly validators.
FooterTemplate Defines the contents and appearance of the row’s footer.
HeaderTemplate Defines the contents and appearance of the row’s header.
ItemTemplate Defines the default contents and appearance of the rows.

A templated view can contain anything that makes sense to the application you’re building – server controls, literals, and data-bound expressions. Data-bound expressions allow you to insert values contained in the current data row. You can use as many fields as needed in a template. Notice, though, that not all templates support data-bound expressions. The header and the footer template are not data-bound, and any attempt to use expressions will result in an exception. The following code shows how to define the item template for a product column.

<asp:templatefield
	headertext=”Product”>
	<itemtemplate>
		<b><%# Eval(“productname”)%></b><br />
		available in <%# Eval(“quantityperunit”)%>
	</itemtemplate>
</asp:templatefield>
Note that the TemplateField class also features a InsertTemplate property. However, this type of template is never used by the GridView control. The InsertTemplate is used by the FormView control instead. As mentioned earlier, in ASP.NET 2.0 view controls share some field classes like TemplateField. As a result, TemplateField (and a few more classes) provide a superset of properties that serves the needs of multiple view controls.

Paging

Like the DataGrid, the GridView control provides a built-in mechanism for paging over the supplied data source. This form of paging requires that the whole data source be bound to the control. To enable paging, all you do is enable paging capabilities on the control. The property to use is AllowPaging. When the AllowPaging property is set to true, the grid displays a pager bar. You can control the characteristics of the pager to a large extent, through the <PagerSettings> and <PagerStyle> tags or their equivalent properties. Unlike the DataGrid, the GridView pager supports first and last page buttons and lets you assign an image to each button. (This is also possible in version 1.x, but it requires a lot of code.)

Note that the GridView control doesn’t have an equivalent of the DataGrid’s AllowCustomPaging property and is limited to exploiting the paging capabilities of the underlying data source. Whether page data is queried at every postback, or is just retrieved from some cache, doesn’t depend on the GridView control.

Regarding paging, the EnablePagingAndSortingCallbacks property toggles on and off the control’s capability to use script callbacks to page and sort without doing roundtrips to the server changing the entire page. In other words, when this feature is enabled any attempt to sort or page the current contents is resolved with a remote method invocation and the page in the browser is refreshed using Dynamic HTML.

Other view controls

Many applications need to work on a single record at a time. ASP.NET 1.x has no built-in support for this scenario. Creating a single record view is possible, but it requires some coding: you have to fetch the record, bind its fields to a data-bound form, and optionally provide paging buttons to navigate between records. Displaying the contents of a single record is a common practice when you build master/detail views. Typically, the user selects a master record from a grid, and the application drills down to show all the available fields. In ASP.NET 2.0, the DetailsView fulfills this role and is the ideal complement to the GridView control for building, easily and effectively, hierarchical views of data.

Like the GridView, the DetailsView control can bind to any data source control and exploit its set of data operations. It can page, update, insert, and delete data items in the underlying data source as long as the data source supports these operations. In most cases, no code is required to set up any of these operations. You can customize the user interface of the DetailsView control by choosing the most appropriate combination of data fields and styles in much the same way that you do with the GridView. Finally, the DetailsView control fully supports adaptive rendering and renders successfully on mobile devices.

The DetailsView control deliberately doesn’t support templates. A fully template based details-view control is the FormView. FormView is a new data-bound control that works like the templated version of the DetailsView. It renders one record at a time picked from the associated data source and optionally provides paging buttons to navigate between records. Unlike the DetailsView control, FormView doesn’t use data control fields and requires the user to define the rendering of each item using templates. The FormView can support any basic operation its data source provides.

In ASP.NET 2.0, data sources, GridView, and DetailsView controls enable a no-code master/detail scenario. A master/detail page contains a master control (such as a GridView) and a detail control (such as a DetailsView), each bound to its own data source. The trick is in binding the detail control to a data source represented by the currently selected record.

<asp:sqldatasource runat=”server”
	id=”MySource”
	:
	selectcommand=”SELECT * FROM
		customers” />
<asp:gridview runat=”server”
	id=”Master”
	datasourceid=”MySource”
	:
	datakeynames=”customerid” />

<asp:sqldatasource runat=”server”
	id=”MyDetailSource”
	:
		selectcommand=”SELECT * FROM
		customers”
		filterexpression=
			”customerid=’@customerid’”>
		<filterparameters>
		<asp:ControlParameter
			Name=”customerid”
			ControlId=”Master”
			PropertyName=”SelectedValue”
			/>
		</filterparameters>
</asp:sqldatasource>

<asp:detailsview runat=”server”
	id=”Detail”
	datasourceid=”MyDetailSource”>
The DetailsView control is bound to a data source filtered by the value of the SelectedValue property on the GridView control. SelectedValue is a new property that returns the value for the DataKeyNames field on the selected row – the key of the selected row. Based on that data row, the DetailsView control arranges a detail view of the record.

Summary

The key shortcoming of ASP.NET 1.x data binding is that it requires too much code for common (virtually boilerplate) operations. This has been addressed by the introduction of data source objects. But data source objects require richer controls that are capable of working with this new model. ASP.NET 2.0 provides two apparently similar grid controls – DataGrid and GridView. The latter is the successor to the former and extends it in a significant manner. The GridView control has been specifically designed for ASP.NET 2.0 and its data binding model; the DataGrid control retains the ASP.NET 1.x design which it has reviewed and adapted to work. The pair of controls DetailsView and FormView are the perfect complement to the GridView.


Dino Esposito is a trainer and consultant for Wintellect where he manages the ADO.NET class. His books include Programming ASP.NET and he is a frequent speaker at industry events such as DevWeek.

You might also like...

Comments

About the author

Dino Esposito United Kingdom

Dino Esposito is an instructor for Solid Quality Mentors, and a trainer and consultant based in Rome. He is the author of various books, including Windows Shell Programming, Instant DHTML Script...

Interested in writing for us? Find out more.

Contribute

Why not write for us? Or you could submit an event or a user group in your area. Alternatively just tell us what you think!

Our tools

We've got automatic conversion tools to convert C# to VB.NET, VB.NET to C#. Also you can compress javascript and compress css and generate sql connection strings.

“Nine people can't make a baby in a month.” - Fred Brooks