Using Nested DataGrids in ASP.NET

Part I: How to Use DataLists and DataGrids in ASP.NET

Common relationships in object-oriented programming are the aggregation, association, and dependency. When object A is composed of and responsible for the lifetime of a contained object B, we call this relationship an aggregation. When object A uses the facilities of another object B but is not responsible for the object’s lifetime, we call this relationship an association. When an object A is dependent for part of its implementation on a second object B, we call this relationship a dependency. If the multiplicity of aggregate, associative, or dependent objects is greater than one then we often employ an array, collection, DataSet, or DataTable to represent the multiplicity of objects.

Many classes exist in the .NET Framework to express relationships between one object A and many objects B, referred to generically as one-to-many relationships. These classes will just as easily permit more complex relationships. For example, each instance of object A may contain one-to-many instances of object B and B may contain one-to-many instances of object C. These relationships are well-understood and can be easily represented with arrays, list, collections, or other data structures. What may be more challenging is representing these nested, complex relationships in the presentation layer.

One could clearly try to write reams of code that dynamically creates controls on the fly, assembling a user interface piecemeal, but such code may be difficult and time consuming to write. A better alternative is to use existing controls that model nested relationships. In this first article I will demonstrate how you can use ASP.NET controls like the DataList and a DataGrid to represent A-B-C relations where B and C represent complex objects and A contains one or more instances of B and B contains one or more instances of C. In part 2 of this article I will demonstrate how to use HTML tables to manage complex layouts and nest DataGrids within DataLists, and part 3 will demonstrate how to support editing a multiplicity of objects presented to the user with ASP.NET controls.

Binding Data to a DataList or DataGrid

The DataList and DataGrid controls can be conveniently used to present repeating objects. The source of the data can be bound directly to the DataList or DataGrid (a Repeater is a good control for read-only data, too), or you can define a template and the DataList and DataGrid will repeat those controls for every object in the source data.

Most of the ways that exist to describe a collection of data can be used as data sources for the DataList and DataGrid. By digging around in the shared source code library (sscli, or Rotor) it looks like the only requirement is that an object implement IEnumerable. This means that any array, collection, list, or ADO.NET data source can be bound directly to a DataList or DataGrid. (I have bound all of these to the DataList and DataGrid, and they work nicely.)

The basic steps for displaying data in a DataList or DataGrid is to assign your object to the control’s DataSource property and called DataBind method. For example, if you place a DataGrid onto an ASP.NET Web Page, assign an array of integers to the DataGrid’s DataSource property and call DataBind the integers will be displayed in the DataGrid. Listing 1 shows the code to display the array of integers.

Listing 1: Display an array of simple data.

Private Sub Page_Load(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles MyBase.Load

  DataGrid1.DataSource = New Integer() {1, 2, 3, 4, 5}
  DataGrid1.DataBind()

End Sub

The two lines of code in listing 1 represent the bulk of work necessary to move data into a DataGrid (or DataList). While the example in listing 1 is very simple, you can use this technique to display a one of a kind object in a DataGrid. For example, if designing a GUI to display a single instance of a Customer object, you can create an array initialized with one Customer object and bind that to the DataGrid or DataList. The DataSource statement could be written as follows:

DataGrid1.DataSource = New Customer(){MyCustomer}

Testing IsPostBack

Binding data is an expensive proposition. Assume that your data source is a database. Running SQL to read data from a database takes some time. Reducing the number of times your code hits the database can improve performance. In the scenario shown in listing 1, where the literal array is replaced with a DataSet, the page would perform the read every single time. However, if the EnableViewState property of the page and control is True (the default state) then the page will automatically save the view state information. By testing the IsPostBack property of the Page you can determine whether or not it is necessary to re-read the data. If IsPostBack is True then the data will be recreated from the view state and no read is necessary. If IsPostBack is False then the data will need to be refreshed and bound to the control. A revision to listing 1, shown in listing 2, demonstrates how to use the IsPostBack property.

Listing 2: Avoiding unnecessary calls to create the data source.

Private Sub Page_Load(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles MyBase.Load

  If( IsPostBack = False ) Then
    DataGrid1.DataSource = New Integer() {1, 2, 3, 4, 5}
    DataGrid1.DataBind()
  End If

End Sub

By simply enabling view state and checking the post back condition you can radically reduce the number of times your ASP.NET applications perform expensive database hits. (In listings 1 and 2 the database hit is not shown but is represented by the assignment to the DataGrid’s DataSource property.)

Using DataList Templates

When using a data source to populate a DataList we define templates. Templates are simply chunks of HTML that describe the controls used to present the data in from each row of the data source. One can define a template by adding controls between the template tags&mdashfor example, <ItemTemplate></ItemTemplate>&mdashHTML in the HTML view of an ASP.NET page or by using the DataList’s designer. To invoke the designer right-click on the DataList and select the template you wish to modify from the Edit Template menu (see figure 1).

Figure 1: Indicate the template you wish to modify by selecting the appropriate context menu.

The designable region looks small (see figure 2) but it is correct to think of the small area (shown circled in figure 1) as capable of containing as much data as a whole Web page. In other words, the template can be as simple or complex as you desire. Admittedly the workspace will feel cramped; for this reason I prefer to define a UserControl which gives me more physical and apparent screen real estate to work with, and then place the UserControl in the template.

Figure 2: You can define as complex or as simple a template as you desire in each template section (shown circled).

Implementing the Item Template

The DataList has a basic drawback relative to the DataGrid: the Datalist does not know how to present data by default. If we bind data to the DataGrid, as shown in listings 1 and 2, then the DataGrid can display the contents of the array. Conversely, without a template&mdashthat is, controls to display the data in&mdashthe DataList will not know how to render the data. In addition to defining the template we must define binding relationships that tell the DataList what data to get from the data source, how to get it, and how to format that data. Ultimately we have more work to do if we elect to use the DataList as the primary control for presenting data.

Follow the numbered steps to convert the DataGrid from listing 2 to a DataList:

  1. Place a DataList on a blank Web page
  2. Right-click on the DataList and select Edit Template|Item Templates
  3. Drag a Label control from the Web Forms tab of the Toolbox into the ItemTemplate section of the DataList (this section is shown circled in figure 2)
  4. Click on the Label in the ItemTemplate section and press F4 to show the Properties Window
  5. Click on the designer button for the Label’s (DataBindings) property and define a custom binding expression for the Label’s Text property (see figure 3). The HTML (switch to the HTML view in the IDE) should be similar to the code shown in listing 3.
  6. Add the code shown in listing 4 to the page’s Page_Load event handler.
  7. Press F5 to test your work. You should see the integers from the data source listed

Figure 3: Define a how data is retrieved from the data source and displayed in controls in the DataList template.

Listing 3: The HTML for the Web page after defining the ItemTemplate and the binding statement.

<%@ Page Language="vb" AutoEventWireup="false"
       Codebehind="WebForm1.aspx.vb"
       Inherits="NestedDataLists.WebForm1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
  <HEAD>
    <title>WebForm1</title>
    <meta name="GENERATOR" content="Microsoft Visual Studio .NET 7.1">
    <meta name="CODE_LANGUAGE" content="Visual Basic .NET 7.1">
    <meta name="vs_defaultClientScript" content="JavaScript">
    <meta name="vs_targetSchema"
             content="http://schemas.microsoft.com/intellisense/ie5">
  </HEAD>
  <body MS_POSITIONING="GridLayout">
    <form id="Form1" method="post" runat="server">
      <asp:DataList id="DataList1" runat="server">
        <ItemTemplate>
          <asp:Label id=Label1 runat="server"
                        Text="<%# Container.DataItem %>">
          </asp:Label>
        </ItemTemplate>
      </asp:DataList>
    </form>
  </body>
</HTML>

Listing 4: The code behind to bind the array of integers to the DataList.

Private Sub Page_Load(ByVal sender As System.Object, _
  ByVal e As System.EventArgs) Handles MyBase.Load

  If (IsPostBack = False) Then
    DataList1.DataSource = New Integer() {1, 2, 3, 4, 5}
    DataList1.DataBind()
  End If

End Sub

Summary

Part one of this three part article demonstrated the basic technique for binding any data source to a DataList and DataGrid. It also demonstrated the basics for defining a data binding statement for the template sections of a DataList. This may be new material to some of you. However, from reading many of the various news groups it looks like many developers have grasped these basic concepts.

In parts two and three of this three part article I will move on to more advanced concepts, including the one that seem to be plaguing a lot of ASP.NET developers: how to edit nested DataGrids. Part two of this article will demonstrate how to use HTML tables to manage complex presentations in DataLists. I will also demonstrate how to nest DataGrids within DataLists and get the data to show up correctly, as well as talk about how to use UserControls as a palette for defining template sections. Part three of this article will demonstrate a practical solution for managing repeated DataGrids, including how to successfully edit the data in these grids.

Stay tuned for parts two and three, which will be concluded in June.

About the Author

Paul Kimmel is a freelance writer for Developer.com and CodeGuru.com. Look for his upcoming book, Visual Basic .NET Power Coding, from Addison-Wesley. Paul Kimmel is available to help design and build your .NET solutions and can be contacted at pkimmel@softconcepts.com.

# # #

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read