Nested grid for displaying hierarchical data (from MSDN)

Source: Internet
Author: User
Tags bind contains extend implement
Data | In the August 2003 issue of "cutting-edge technology", I discussed how to extend the ASP.net DataGrid server control to use a multiple table data container, such as a DataSet object, as its data source. If the DataSet contains several pairs of related tables, the control adds a dynamically created button column as long as the table displayed is the parent of one of the relationships. When you click the Column button, the child DataGrid is displayed and the child rows of the selected records are listed based on this relationship. The overall behavior is shown in Figure 1, which works the same way as the Windows® forms DataGrid control does in similar situations.



Figure 1 Parent and child DataGrids

The application shown in Figure 1 is a user control that contains two DataGrid controls that work together. The user control (see Source code for August 2003) contains all the logic required to keep the two grids synchronized. The parent DataGrid binds to the DataSet and displays the contents of the parent table. When this occurs, the user control ensures that there is a relationship within the DataSet (the table in which it appears to act as a parent). A child DataGrid is bound to a data view that contains all the records in a child table that is related only to the selected record. So, if you have a DataSet and it has two relational tables, the user control will save you time because you don't need to write code for any additional display mechanisms.

So what's wrong with this approach? If you just focus on basic functionality, then it's fine. However, some readers have noticed that it might be better not to use two physically delimited DataGrid controls. The user control constructs a barrier around the control that makes it possible for you to access these constituent controls only by mapping properties and methods or by exposing the entire internal control. From a programmable point of view, it is much simpler to use a DataGrid control to display hierarchical data. First, you don't have to worry about the configuration of the parent table. Just use the standard interface of the DataGrid control. Any child grids that display related data can be created dynamically and can be displayed inside the layout of the main network.



Figure 2 Embedded sub-DataGrid

On the other hand, you need to be reminded that the DataGrid control is not designed to contain hierarchical data. Its internal layout is best for displaying tabular data. The DataList control may be a good choice, but it does not provide intrinsic paging support and requires some code to work like a DataGrid. When you quickly search for "nested DataGrid" on Google, a link to the article that discusses how to embed the DataGrid in the DataList control is returned, which gives me some hints about this column. Here, I'll construct a custom control that inherits from the DataGrid class. The control implements a custom column type (Expandcommandcolumn) and contains all the logic necessary to display the records associated with the clicked item. The expand view is represented by a child DataGrid embedded in the parent. Figure 2 shows the appearance of this control.

Constructing nested grids

A hierarchical DataGrid control makes sense only if the data source is a DataSet object that contains a relationship between tables. For example, suppose a DataSet has a Customers table and an Orders table, and the DataRelation between the two tables is established on the CustomerID column. As long as the DataGrid contains a button column, when you click it, you can create a child view for the selected customer and bind the generated DataView object to the child grid.

Because the new control (called Nestedgrid in the example code) is inherited from the DataGrid class, it can be used in any case where it is appropriate to use the DataGrid object. But this last sentence has yet to be modified. Typically, when you derive a control from a base class, it is possible that the derived control cannot replace the original control because of its specific extension and additional items. In this column, I won't spend much time making the Nestedgrid component backward compatible with the base DataGrid class. For simplicity's sake, I assume that you always bind it to a DataSet object.

There are several other assumptions about the Nestedgrid control, which will be explained gradually in the later section. Specifically, you are responsible for adding button columns that specify the expanded/collapsed status of each row. Theoretically, the column can be placed anywhere in the grid. But I'm here to assume that the expansion column is the first column in the grid. (as discussed in the August 2003 issue, the behavior can be modified appropriately so that the column is dynamically generated only when the DataGrid is bound to a DataSet with related tables.) )

If you've ever had a bit of experience using the DataGrid control, you know that although it is extremely powerful and customizable, it does not support layout changes very well. Grid layouts represent tabular data-rows that are equal in size by rule. How can I embed a child grid with this limit?

The important point to be reminded here is that the grid is rendered as a standard HTML table. Once a cell has a regular table layout, you can put anything in each cell, including a child table that represents a child grid (using the rowspan tag). First, delete all cells other than the cell that contains the command button to modify the number of cells that make up the selected row (that is, the row on which the expand command button that the user clicked) is located. This is easy to implement if you assume that the expand command column is on the left. After all the cells have been deleted, you can create a new cell that spans several columns (the number of columns must equal the number of items in the Columns collection of the DataGrid control).

At this point, you already have a fully custom cell that makes the row expandable. You can programmatically populate any combination of server controls in this custom cell. For example, you can insert a table that simulates the structure of a deleted cell (usually information about the parent row), and the bottom row contains the child DataGrid. The controls in Figure 2 are created based on this scenario.

Nestedgrid class

As mentioned earlier, the Nestedgrid class inherits from the System.Web.DataGrid class and adds several additional attributes (see Figure 3). This control will also raise a custom Updateview event when data binding is required. To strictly control the type of object assigned to the DataSource property (and make sure it is a DataSet), you can override the DataSource property as shown in the following code:

public override Object DataSource
{
get {return base. DataSource;}
set {
if (!) ( Value is DataSet)) {
Throw an exception
}
Base. DataSource = value;
}
}

The Nestedgrid control is instantiated when the user clicks the row button to expand the record (an account) to view its details. To do this, a nested grid must contain a button column with some specific functionality. First, the grid must provide handlers for the ItemCommand event so that the expansion/collapse request can be processed. The handler sets the Expandeditemindex property to the zero-based index of the clicked record and updates the grid view. So when is the layout appropriate to modify the rows clicked?

When the grid layout is created, the ItemDataBound event fires at the bottom of the event chain. After the ItemDataBound is fired, the data binding phase is basically complete and all the cells can be displayed. The layout and data that you see thereafter will not change any more. It is for this reason that I have decided to implement all the necessary changes before handling the ItemDataBound event.

There are a few caveats to ask before delving into the implementation of the control. First, the Expandeditemindex property is based on zero, but it represents the absolute position of the row that is clicked. The only difference between this property and a similar grid property, such as Selecteditemindex and EditItemIndex, is that it represents a value that is not based on the page. Second, Nestedgrid is also implementing pagination internally. In order for the control to move between pages in a member table, you do not have to do anything other than handle the Updateview event and pass the bound data:

void Updateview (object sender, EventArgs e) {
Binddata ();
}
void Binddata () {
Datagrid.datasource = (DataSet) cache["MyData"];
Datagrid.databind ();
}

The Nestedgrid class has a built-in handler for the PageIndexChanged event, as follows:

void PageIndexChanged (object sender, DataGridPageChangedEventArgs e)
{
CurrentPageIndex = E.newpageindex;
SelectedIndex =-1;
EditItemIndex =-1;
Expandeditemindex =-1;

if (Updateview!= null)
Updateview (this, eventargs.empty);
}

A key element of the structure of a Nestedgrid control is a button column. For simplicity, this version of the control supports only a single expanded item. You can easily extend this functionality by changing the Expandeditemindex property from an integer to an array or collection.

Expandcommandcolumn class

You can use strings, such as "+ +" or "expand/collapse", or bitmaps to render an expanded column. You may want to use a different picture for different applications. The most flexible way to implement this feature is to use several properties such as Expandtext and Collapsetext. So, should you define these properties on the Nestedgrid class? In a similar scenario (in-place editing), the ASP.net development team created a custom DataGrid column with attributes such as EditText, Canceltext, and UPDATETEXT in the column. Based on this, I created my own Expandcommandcolumn class and placed several text attributes in it to represent the HTML output used to expand and collapse the view. The following code fragment shows how to integrate the custom column with the grid.

<cc1:nesteddatagrid id= "DataGrid" runat= "Server" ...>
<Columns>
<cc1:expandcommandcolumn
collapsetext= "expandtext=



Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.