Nested GridView with TreeView Like Structure
By AzamSharp
Views: 7721

Introduction:

Displaying hierarchical data is a common feature practiced by many websites. Hierarchical data can be displayed in many different ways. In this article we will learn how to display nested data using nested GridView controls.

The Domain Model:

The domain model is really simple and consists of two entities, Category and Products. A single category can have multiple products hence producing the one-to-many relationship. This article does not contain any persistent storage like database or xml files and the entities are populated at runtime.

Populating the Entities:

Since, we are not using any database we need to populate the entities manually. This can easily be accomplished by using nested for loops. Take a look at the code below which creates several categories and adds few products to each of the category.

private List<Category> _categories = new List<Category>();
private List<Category> GetCategories()
        {
           _categories = new List<Category>();

            for (int i = 1; i <= 20; i++)
            {
                Category category = new Category();
                category.Id = i;
                category.Name = String.Format("Category {0}", i);

                for (int j = 1; j <= 3; j++)
                {
                    Product product = new Product();
                    product.Id = j;
                    product.Name = String.Format("Product {0} of Category {1}", j,i);

                    category.Products.Add(product);
                }

                _categories.Add(category);
            }

            return _categories;
        }

In the code above we are simply creating some dummy categories and adding dummy products to each category.
The BindData method is responsible for binding the categories to the GridView control.

private void BindData()
        {
            gvCategories.DataSource = GetCategories();
            gvCategories.DataBind();
        }

The GridView will look something like this: 

Displaying the Products GridView as a Child GridView:

To display products GridView as a child GridView we need to add it to the ItemTemplate of the categories GridView. Check out the code below which shows the products GridView added to the Categories GridView.

<asp:GridView ID="gvCategories" CssClass="grid" GridLines="none" runat="server" AutoGenerateColumns="false">
   
    <Columns>
   
    <asp:TemplateField HeaderText="Category Name">
    <ItemTemplate>  
   
   <%# Eval("Name") %>
   
    <asp:GridView CssClass="innerGrid" GridLines="None" ID="gvProducts" runat="server" AutoGenerateColumns="False" DataSource='<%# Eval("Products") %>' CellPadding="4" DataSourceID="" ForeColor="#333333">   
    <Columns>
      
    <asp:TemplateField>
   
    <ItemTemplate>
   
    <%# Eval("Name") %>
   
    </ItemTemplate> 
   
    </asp:TemplateField>
    </Columns>
    </asp:GridView>
   
   
</ItemTemplate>   
    </asp:TemplateField>
   
    </Columns>
   
    </asp:GridView> 

And here it the result: 


 
So, now we can see the child products under each category. Although this is what we were after but this does not look good. We need to add some behavior so that we can expand and collapse the products.

Creating Expand and Collapse Functionality:

We will be using a “+” sign image to expand and “-“ sign image to collapse the products GridView. To write minimal code we will be leveraging the power of the Prototype JavaScript Library. You are free to use any library that you desire.
Let’s first add the “+” sign to our products GridView. Check out the following code:

<asp:GridView ID="gvCategories" CssClass="grid" GridLines="none" runat="server" AutoGenerateColumns="false">
   
    <Columns>
   
    <asp:TemplateField HeaderText="Category Name">
    <ItemTemplate>  
   
   <a id="openCloseLink" onclick="toggleDetailsView(this)" href="#">
    <img src="tn_plus.GIF" style="border: 0px;" alt="PLUS" />
    </a>
   
    <span class="mainTitleStyle">
    <%# Eval("Name") %>
   </span>
   
    <asp:GridView CssClass="innerGrid" GridLines="None" ID="gvProducts" runat="server" AutoGenerateColumns="False" DataSource='<%# Eval("Products") %>' CellPadding="4" DataSourceID="" ForeColor="#333333">   
    <Columns>
      
    <asp:TemplateField>
   
    <ItemTemplate>
   
    <%# Eval("Name") %>
   
    </ItemTemplate> 
   
    </asp:TemplateField>
    </Columns>
    </asp:GridView>
   
    </ItemTemplate>   
    </asp:TemplateField>
   
    </Columns>
   
    </asp:GridView>
And here is the result:
 
Now, we need some way to hide the products GridView. This is achieved by adding a simple “DIV” tag.

<div id="divDetailsView" runat="server" class="collapsed">
// Products GridView
</div>

The class “collapsed” is responsible for hiding the “DIV” element which in turn hides the contained GridView control.  Check out the effect below: 


This is much better! Now, the user can see all the categories collapsed and can decide which one to expand.
Wait! It is not over yet. We still need to implement the JavaScript functions which trigger the show and hide of the products GridView.

Client Side Implementation to Toggle Nested GridView:

The toggleDetailsView function is responsible for collapsing and expanding the nested products GridView.

var className = 'collapsed';   
function toggleDetailsView(link)
{
    // change HTML text to open and close
   
    var img = $(link).childElements()[0];    
       
    var imgFileName = getFileNameFromUrl(img.src);
   
    img.src = imgFileName == 'tn_plus.GIF' ? 'tn_minus.GIF' : 'tn_plus.GIF';    
            
    var element = $(link).next("." + className);    
   
    $(element).toggleClassName('expanded');
   
}

First, we get the image element which is contained as a child of the anchor element. The getFileNameFromUrl function is used to get only the file name from the image URL. After we get the file name we simply toggle the image between “tn_plus.GIF” and “tn_minus.GIF”.  The line var element = $(link).next("." + className); gets the element which has the class name “collapsed”. Finally, the Prototype.js method toggleClassName is used to toggle the class between “collapsed” and “expanded”.

Conclusion:

In this article we learned how to display nested data using nested GridView. We also implemented a nice toggle effect which enabled the users to expand and collapse the child items.

[Download Sample]

By AzamSharp




Enter Comment/Feedback
  •  
  •  
  •  
  •  
  •  

Comments/Feedbacks
Subject: Error
Name: Rajendra
Date: 7/25/2008 3:12:47 AM
Comment:
I have downloded the sample. But on running the application, I got the following Error : ASP.NET runtime error: It is an error to use a section registered as allowDefinition='MachineToApplication' beyond application level. This error can be caused by a virtual directory not being configured as an application in IIS.
Subject: re: virtual directories
Name: AzamSharp
Date: 7/25/2008 12:51:10 PM
Comment:
Hi,

Try setting the directory as the virtual directory.
Subject: Error
Name: Rajendra
Date: 7/27/2008 8:37:00 PM
Comment:
I have copied the downloaded source code in a folder and on executing I got an error. Kindly let me know how I can set a directory or a folder as virtual directory.
Subject: RE: Error
Name: AzamSharp
Date: 8/3/2008 10:39:19 AM
Comment:
Hi Rajendra,

What is the error?
Subject: Error
Name: Rajendra
Date: 8/4/2008 10:28:31 PM
Comment:
After running the project in VS 2005, I got the following error :
Error 1 It is an error to use a section registered as allowDefinition='MachineToApplication' beyond application level. This error can be caused by a virtual directory not being configured as an application in IIS. D:\raju1\NestedGridViewPlusMinus\NestedGridViewPlusMinus\NestedGridViewPlusMinus\Web.config 21

Please rply the solution
Subject: client side functionality
Name: jai ganesh
Date: 8/10/2008 8:29:20 AM
Comment:
i am not able to ge t the client side functionality ie the collapse and show
Subject: re: client side functionality
Name: AzamSharp
Date: 8/11/2008 1:17:53 PM
Comment:
Hi Jai,

Please download the project and check out the code samples!
Subject: Multiple columns on Parent gird
Name: James
Date: 9/14/2008 11:37:19 AM
Comment:
I'm trying to do the same here but have the requirement of having to have multiple columns (all on one row with headers) and then having the child grid immediately under the parent row. I can I do this?
Subject: Good article
Name: Siva
Date: 9/16/2008 3:31:23 AM
Comment:
Hi Azam,

Very informative, precise and impeccable article. Well done. Keep up the good work.
Win a free book
You can win yourself ASP.NET AJAX in ACTION
Read details







Join WebHost4Life.com







Copyright GridViewGuy 2007-2008