devxlogo

A Not-So-Quick Tour of the Web DataGrid Control

A Not-So-Quick Tour of the Web DataGrid Control

ata-bound controls play a key role in the development of ASP.NET applications. Data-driven controls allow you to associate their whole interface, or individual properties, with one or more columns of a .NET-compliant data source. In this article, I’ll delve into the depths of an extremely versatile data-bound control that is a fixed presence in any real-world ASP.NET application?the DataGrid control. I’ll focus on the key programming aspects of the control, including data binding, column mapping, paging, and sorting.

The DataGrid server control renders a multi-column, fully templated, data-bound grid and provides a highly customizable, Excel-like user interface. Bound to a DataGrid, the data source renders through an HTML table interspersed with HTML elements and hyperlinks. You can customize the contents of the cells in each column to some extent using system-provided, as well as, user-defined templates. The DataGrid supports various types of data-bound columns, including text, templated, and command columns. The data binding mechanism is nearly identical to that of other ASP.NET controls. You bind the data source using the DataSource property, but no data will actually load until you call the DataBind method.

You can set most of the DataGrid features declaratively in the page layout; the same set of attributes, though, are also available programmatically through the properties and methods of the DataGrid class.

Simple Data Binding
The following line of code is enough to enable grid functionality in a Web page. It declares a server-side instance of the DataGrid control and assigns it the name of grid. All of the code associated with the page, refers to the DataGrid using the specified ID. The ASP.NET runtime takes care of creating and initializing such an instance for each request.

   

Once you’ve placed the control onto the page, you bind it to the data source and display the resulting HTML code. The following code binds a DataTable to the grid.

   void Page_Load(object sender, EventArgs e)   {      // Run the query and get    // some data to display      DataTable data = ExecuteQuery(cmdText,         connString);      // Bind the data to the grid       grid.DataSource = data;      grid.DataBind();   }   DataTable ExecuteQuery(string cmdText,       string connString)   {      SqlDataAdapter adapter;      adapter = new SqlDataAdapter(cmdText,          connString);      DataTable data = new DataTable();      adapter.Fill(data);      return data;   }

Although effective in terms of retrieval and display, you probably would not use this code in real applications because as Figure 1 shows, the resulting DataGrid control doesn’t implement necessary features and the interface is too plain.

The Programming Interface
The DataGrid control has no method specific of the class. It inherits all the methods it provides (for example, DataBind) from the various base classes. The DataGrid inherits from the BaseDataList class and implements the INamingContainer interface. The BaseDataList abstract class inherits from WebControl and provides a common set of functionality for all data listing controls, including the DataList and the DataGrid. The INamingContainer interface is a marker interface that doesn’t require the implementation of any methods but only indicates that the class has some features. In particular, the interface marks the class as a naming container. A naming container is a class that provides an ID namespace for their child controls. Controls that act as naming containers guarantee that the ID attributes of their child controls are unique within the entire application?a key point for all controls that contain a subtree of controls.

Table 1 details the list of properties supported by the DataGrid control, but doesn’t include the properties inherited by the BaseDataList and WebControl classes.

Table 1: Properties of the DataGrid class.

Property

Description

AllowCustomPaging

Indicates whether you’ve enabled custom paging. You must set AllowPaging to true for this setting to work.

AllowPaging

Indicates whether you’ve enabled paging.

AllowSorting

Indicates whether you’ve enabled sorting.

AlternatingItemStyle

Returns the style properties for alternating rows.

AutoGenerateColumns

Indicates whether you want to permit the creation and display of column objects for each field in the data source. True by default.

BackImageUrl

Indicates the URL of the image to display as the background of the control.

CellPadding

Indicates the space (in pixels) left between the cell’s border and the embedded text.

CellSpacing

Indicates the space (in pixels) left between two consecutive cells both horizontally and vertically.

Columns

Returns a collection of DataGridColumn objects that represent the columns in the DataGrid control.

Controls

Returns the collection of all the child controls in the grid.

CurrentPageIndex

Indicates the index of the currently displayed page.

DataKeyField

Indicates the key field in the bound data source.

DataKeys

Returns a collection that stores the key values of all the records displayed as a row in the grid. You use the DataKeyField property to define the column that you want to use as the key.

DataMember

A string that indicates the specific table in a multimember data source to bind to the grid. The property works in conjunction with DataSource. If DataSource is a DataSet object, then DataMember contains the name of the particular table to bind.

DataSource

Indicates the data source object that contains the values to populate the control.

EditItemIndex

Indicates the index of the grid’s item to edit.

EditItemStyle

Returns the style properties for the item being edited.

FooterStyle

Returns the style properties for the footer section of the grid.

GridLines

Indicates whether all cells must have the border drawn.

HeaderStyle

Returns the style properties for the heading section of the grid.

HorizontalAlign

Indicates the horizontal alignment of the text in the grid.

Items

Returns the collection of the currently displayed items.

ItemStyle

Returns the style properties for the items in the grid.

PageCount

Gets the number of pages required to display all bound items.

PagerStyle

Returns the style properties for the paging section of the grid.

PageSize

Indicates the number of items to display on a single page.

SelectedIndex

Indicates the index of the currently selected item.

SelectedItem

Gets a DataGridItem object that represents the selected item.

SelectedItemStyle

Returns the style properties for the currently selected item.

ShowFooter

Indicates whether or not to display the footer. False by default.

ShowHeader

Indicates whether or not to display the header.

VirtualItemCount

Indicates the virtual number of items in the DataGrid control when you choose to use custom paging.

Many of the properties allow you to improve the grid’s look and feel. When setting attributes, you can either set the property individually at the level, or group related properties together on a per-item basis. For example, if you want to set the background color of the column headers to a particular color, you can do that through the headerstyle-backcolor attribute at the root level, as shown in the following code.

   

However, you can also define the e child node within the declaration and set its BackColor attribute.

         :   

The effect is the same, but the second option looks more elegant and is easier to maintain. Visual Studio .NET generates this type of code when you drop a DataGrid control on a Web form. The following schema illustrates the overall ASP.NET layout of the control.

                                                      :         

The output of a DataGrid control consists of several constituent elements grouped in the ListItemType enumeration. (See Table 2 for more information.) Each element plays a clear role and has a precise location in the control’s user interface as Figure 2 shows.

Table 2: The ListItemType enumeration.

Item type

Description

AlternatingItem

Represents a data-bound row placed in an odd position. Useful if you want to use different styles for alternating rows. AlternatingItemStyle is the property that lets you control the look and feel of the element.

EditItem

Represents the item, or alternating item, currently displayed in edit mode. EditItemStyle lets you control the look and feel of the element.

Footer

Represents the grid’s footer. You cannot bind the element to a data source and you set its style using the settings in the FooterStyle property.

Header

Represents the grid’s header. You cannot bind the element to a data source and you set its style using the settings in the HeaderStyle property.

Item

Represents a data-bound row placed in an even position. Styled through the ItemStyle property.

Pager

Represents the pager element that you use to scroll back and forth between pages. You cannot bind the element to a data source and you set its style using the settings in the PagerStyle property. You can place the pager at the top or the bottom of the grid’s table and even in both places.

SelectedItem

Represents the item, or alternating item, currently selected. The SelectedItemStyle property defines the look and feel of the element.

Binding Data to the Grid
A DataGrid control is composed of a number of data-bindable columns. By default, the control includes all the data source columns in the view. You can change this behavior by setting the AutoGenerateColumns property to false. In this case, the grid displays only the columns explicitly listed in the Columns collection. The DataGrid control supports a variety of column types, which mostly differ from one another in how each represents the data. You must indicate the type of column if you add it to the Columns collection; otherwise, automatic generation will create only columns of the simplest type?the BoundColumn column type. Table 3 lists all of the column types available. Table 3: Column types.

Column Type

Description

BoundColumn

Displays each cell as plain text. The contents of the column are bound to a field in a data source.

ButtonColumn

Displays a command button for each item in the column. The text of the button is data-bound. The command name of the button must be common to all the items in the column. You can control the graphical style of the button, push button or link button.

EditColumn

A particular type of button column associated with a command named Edit. When in edit mode, the DataGrid draws the whole row using text boxes rather than literals.

HyperLinkColumn

Displays the contents of each item in the column as a hyperlink. You can either bind the text of the hyperlink to a column in the data source or it can be static text. You can also make the target URL data-bound too. Clicking a hyperlink column causes the browser to jump to the specified URL. Supports target frames.

TemplateColumn

Displays each cell of the column following a specified ASP.NET template. This allows you to provide custom behaviors.

You normally bind columns using the tag in the body of the server control, as the following code demonstrates.

        :                                        /columns>   

Alternatively, you can create a new column of the desired class, fill its member properly, and then add the class instance to the Columns collection. Here is the code to add a BoundColumn object to a grid.

   BoundColumn bc = new BoundColumn();   bc.DataField = "firstname";   bc.HeaderText = "First Name";   grid.Columns.Add(bc);

The order of the columns in the collection determines the order of the columns in the DataGrid control. A BoundColumn object key properties include a DataField, which represents the name of the column to bind, and a DataFormatString, which allows you to format the displayed text. The previous code snippet adds two columns and specifies the header text and the source column for each. In addition, the second column is right aligned and given a format string to make it look like a currency value. The text of a bound column is always rendered using literal text.

The HyperLinkColumn class is a column type that contains a hyperlink for each cell. The programmer controls the text of the hyperlink (property DataTextField) and the URL (property DataNavigateUrlField). You can bind both fields to a column in the data source.

           

When you click the cell of a hyperlink column, the browser jumps to the specified URL and displays the linked contents in the window specified by the Target property. Feasible values for the Target property include a few special names like _self, _blank, _top, plus any name that individuates a frame window. If you have not set a target then the current page will refresh.

You can set most of the DataGrid features declaratively in the page layout.

In Figure 3, the yellow box to the right of the grid is an inline frame with a modified border. The frame refreshes whenever the user clicks a column hyperlink. You can use column names to format the URL. In the DataNavigateUrlFormatString property you define the URL with a one column placeholder identified by the {0} expression. The macro will expand at runtime using the value read from the column specified by the DataNavigateUrlField property.

Paging the Grid’s Contents
In real-world scenarios, the size of the data source easily exceeds the real estate of the page. Many applications use data paging to gain scalability and present a more helpful page to the user. Especially on the Web, displaying only a few rows at a time is a more effective approach than downloading hundreds of records that stay hidden most of the time. The DataGrid control provides some built-in facilities that let the programmer easily switch to a new page according to the user’s clicks. The control needs to know how many items to display per page, what type of functionality you require for the pager, and the data source to page through. In return, the control tracks the current page index, extracts the rows that fit into the particular page, and refreshes the user interface. Whenever the page index changes, the control files the PageIndexChanged event to the application.

The DataGrid supports two types of paging?built-in paging and custom paging. Built-in paging assumes that all the records that you scroll through are memory resident. The DataGrid is bound to the source all the time and automatically extracts and displays only the rows that fit on a particular page. Notice that the page’s view state does not save the data source; henceforth you must rebind the data source at each postback.

Just because the data source gets lost at each response, caching is vital for effective paging. You download all the data the first time your user access the page, store the data set into the application’s Cache object or session memory, and rebind that data to the control until the application or session is over.

In real-world applications, data caching is a double-edged sword. On one hand, it significantly speeds up data retrieval; on the other hand it taxes the Web server’s memory and potentially affects the overall scalability of the application. You also need to carefully consider the scope of the data. If all sessions share the data and that data doesn’t get stale often, then you can store it once in a global object. If you need to store a distinct copy of the data for each session, then the default built-in paging is probably not the smartest approach you can take. It requires a lot of memory and, even worse, pushes an application architecture that doesn’t scale well.

Custom paging is designed to work around the data cashing risks. When you enable custom paging, the DataGrid assumes that you want to display all the records in the data source on the page. In this case, the DataGrid doesn’t even attempt to extract a page from the bound data. The application is therefore responsible for ensuring that, at any time, the data source contains only the records for the current page. With custom paging your application downloads a small subset of data from the database at each request. If you opt for built-in paging, the following code snippet summarizes the layout of the page data access layer.

   void Page_Load(object sender, EventArgs e) {      if (!IsPostBack)       {         LoadDataFromDatabase();         BindData();         :      }      :   }   void LoadDataFromDatabase() {      DataTable data = ExecuteQuery(cmdText,    connString);      Cache["AppData"] = data;   }   void BindData() {   DataTable data = (DataTable)    Cache["AppData"];      :      grid.DataSource = data;      grid.DataBind();   }

The data loads only once and it gets cached in memory. Whenever the page posts back, the application retrieves data from the cache and binds it to the DataGrid control.

To enable paging in a DataGrid control you must set the AllowPaging property to true. When you turn the property on, the control user interface automatically acquires an extra component?the grid pager. The pager is a built-in toolbar with links to move from one page to the next or to previous pages. You normally configure the pager declaratively by specifying the working mode and a few visual settings. The PageSize property lets you control the maximum number of rows that each page should contain. By default, this value is set to 10.

After you turn the pager on, you’re only half way there. The pager is displayed and updated, but is not functional until you write and register a handler for the DataGrid’s PageIndexChanged event.

   

The delegate for the PageIndexChanged event is shown below. It passes down to the handler a data structure of type DataGridPageChangedEventArgs.

   public delegate void      DataGridPageChangedEventHandler(      object source,      DataGridPageChangedEventArgs e);

The class inherits from EventArgs and features two extra properties?CommandSource and NewPageIndex. The former represents the source of the event. Since the event only fires when a user clicks a button in the pager, the event source is nothing more than the pager itself?that is, a DataGridItem object. The NewPageIndex property contains the updated index of the page. The DataGrid’s internal engine calculates the correct index of the new page based on the button that the user actually clicked. The following code shows the typical (and minimal) page changed handler for a DataGrid control. It sets the grid’s CurrentPageIndex property with the new page index and rebinds to the data.

   void PageIndexChanged(object sender,   DataGridPageChangedEventArgs e)     {      grid.CurrentPageIndex = e.NewPageIndex;      BindData();   }

When the DataGrid’s DataBind method executes, the control extracts the subset of rows from the data source that fits onto the current page. The rest of the code in the DataBind method loads those records into the Items collection and uses the records in the collection to generate the HTML output for the control.

The pager component is a table row made of a single cell that spans the whole width of the grid. The DataGrid provides some built-in properties to let you customize the pager bar both declaratively and programmatically. In particular, you can choose between two display modes?numeric pages and next-prev mode.

By default, the pager is made of two link buttons pointing to the previous and the next page respectively. The default text associated with these links is for the previous button and > for the next button. You can change the text for each link using the PrevPageText and NextPageText properties. The following code demonstrates how to configure the pager using the element.

   

The font of the pager is set to Webdings. According to this font, the strings 3 and 4 are equivalent to the characters ? and ?.

The DataGrid supports various types of data-bound columns, including text, templated, and command columns.

The display mode of the pager is controlled by the Mode property whose feasible values are NumericPages and NextPrev. The Mode property takes its values from the PagerMode enumeration. The default setting is NextPrev and results in two buttons, one to move to the previous page and one to jump to the next page. The DataGrid control automatically enables and disables the links according to the index of the current page.

When working in numeric pages mode, the pager displays as many links as there are pages in the data source. The PageCount read-only property provides the total number of available pages. Figure 5 provides a side-by-side view of the two interfaces (NumericPages on the left and NextPrev on the right).

Sorting the Data
To enable the DataGrid’s sorting capabilities, set the AllowSorting property to true. When you enable sorting, the DataGrid renders column header text as links. You can associate each column with a sorting expression using the SortExpression property. A sorting expression is any comma-separated sequence of column names. You can enrich each column name with an order qualifier such as DESC or ASC. DESC indicates a descending order, while ASC (the default) denotes the ascending order. If omitted, the column will sort ascendingly. The following code sets up the DataGrid column for sorting on the productname data source column.
               :   

As Figure 7 shows, the header of the column is rendered as a link. When you click on the link, the page posts back and runs the code associated with the SortCommand event.

devxblackblue

About Our Editorial Process

At DevX, we’re dedicated to tech entrepreneurship. Our team closely follows industry shifts, new products, AI breakthroughs, technology trends, and funding announcements. Articles undergo thorough editing to ensure accuracy and clarity, reflecting DevX’s style and supporting entrepreneurs in the tech sphere.

See our full editorial policy.

About Our Journalist