Member Avatar for nixx

Hi!

I was wondering if anybody here could help guide me in the right direction for creating a gridview that contains rows that collapse with another gridview inside. I know we're not supposed to actually ask for codes but I haven't written one yet, I'm just asking for pointers :)

I'm trying to make it look like the jpg i attached.

Any help would be appreciated. Thanks! :)

Recommended Answers

All 4 Replies

Member Avatar for nixx

So far, this is what I've got:

<%@ Page Title="" Language="C#" MasterPageFile="~/MASTERPAGES/master.master" AutoEventWireup="true" CodeFile="nestedGridviewTest.aspx.cs" Inherits="PAGES_nestedGridviewTest" %>

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
    <asp:GridView ID="gvGroup" runat="server" AutoGenerateColumns="false" CssClass="gv gvGroupList"
    AllowPaging="false" AllowSorting="false" OnRowCommand="gvGroup_OnRowCommand" DataKeyNames="ID">
        <Columns>
            <asp:TemplateField>
                 <HeaderTemplate>
                    <asp:CheckBox runat="server" ID="chkAll" AutoPostBack="true" CssClass="DisableValidation"/>
                </HeaderTemplate>
                <ItemTemplate>
                    <asp:CheckBox ID="chkDelete" runat="server" name="chkDel"/>
                </ItemTemplate>
                <ItemStyle CssClass="gvCellCenter gvSelect" />                    
                <HeaderStyle CssClass="gvHeader gvSelect" />
            </asp:TemplateField>
            <asp:TemplateField HeaderText="Group">
                <ItemTemplate>
                    <asp:Label ID="lblIndicator" runat="server" Text="0" Visible="false" />
                    <asp:LinkButton ID="lnkName" runat="server" CommandName="Skills" Text='<%# bind("Name") %>' CommandArgument='<%# DataBinder.Eval(Container, "RowIndex") %>' />    
                </ItemTemplate>
                <ItemStyle CssClass="gvCell" />
            </asp:TemplateField>
            <asp:BoundField HtmlEncode="false" DataField="Description" HeaderText="Description" SortExpression="Description">
                <ItemStyle CssClass="gvCell" />
            </asp:BoundField>
        </Columns>
    </asp:GridView>
</asp:Content>
using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Data;
using Test.Data;
using Test.Business;
using System.Linq.Expressions;
using Test.Common;
using Test.Security;

public partial class PAGES_nestedGridviewTest : System.Web.UI.Page
{
    #region Properties
    private int SelectedIndex
    {
        get { return (int)ViewState["RowIndex"]; }
        set { ViewState["RowIndex"] = value; }
    }
    #endregion

    #region Events
    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            populateGridView();
        }
    }

    protected void gvGroup_OnRowCommand(object sender, GridViewCommandEventArgs e)
    {
        SelectedIndex = int.Parse(e.CommandArgument.ToString());
        Label lblIndicator = (Label)gvGroup.Rows[SelectedIndex].FindControl("lblIndicator");
        int LastCellPosition = gvGroup.Rows[SelectedIndex].Cells.Count - 1;
        int NewCellPosition = gvGroup.Rows[SelectedIndex].Cells.Count;

        if (e.CommandName == "Members")
        {
            if (lblIndicator.Text == "0")
            {
                int GroupID = Convert.ToInt16(gvGroup.DataKeys[SelectedIndex].Value);
                List<Member> MemberList = GroupBL.RetrieveMemberByGroup(GroupID);

                //create a new gridview
                GridView newGV = new GridView();
                newGV.AutoGenerateColumns = false;
                newGV.AllowPaging = false;
                newGV.AllowSorting = false;
                newGV.CssClass = "gv";
                newGV.Width = Unit.Percentage(100);
                newGV.ID = "gvGroup_" + GroupID + "_Members";

                //define the columns of the nested gridview
                addCheckBoxes(newGV);
                addColumns(newGV, "Name", "Name", HorizontalAlign.Left);
                addColumns(newGV, "Description", "Description", HorizontalAlign.Left);
                addColumns(newGV, "Comments", "Comments", HorizontalAlign.Left);

                //bind the nested gridview
                newGV.DataSource = generateTable(MemberList);
                newGV.DataBind();

                //create the remove button
                Button btnRemoveMembers = new Button();
                btnRemoveMembers.ID = "btnRemoveMembers";
                btnRemoveMembers.Text = "Remove";

                //create a panel/div below the selected row
                Panel UP = new Panel();
                UP.BorderStyle = BorderStyle.None;
                UP.BackColor = System.Drawing.Color.White;
                UP.Width = gvGroup.Width;
                UP.ID = "uniquename" + SelectedIndex;
                UP.CssClass = "panelChild";

                //add the controls to the panel/div
                UP.Controls.Add(btnRemoveMembers);
                UP.Controls.Add(newGV);
                UP.Visible = true;

                //Render New GridView to DIV
                System.IO.StringWriter sw = new System.IO.StringWriter();
                System.Web.UI.HtmlTextWriter htw = new System.Web.UI.HtmlTextWriter(sw);
                UP.RenderControl(htw);
                string DivBody = sw.ToString();

                if (SelectedIndex % 2 == 0)
                {
                    gvGroup.Rows[SelectedIndex].Cells[LastCellPosition].Text += "<tr><td  bgcolor='white' colspan='" + NewCellPosition + "'>" + DivBody;
                }
                else
                {
                    gvGroup.Rows[SelectedIndex].Cells[LastCellPosition].Text += "<tr><td bgcolor='lightgrey' colspan='" + NewCellPosition + "'>" + DivBody;
                }

                lblIndicator.Text = "1";
            }

            else
            {
                LastCellPosition = gvGroup.Rows[SelectedIndex].Cells.Count - 1;
                gvGroup.Rows[SelectedIndex].Cells[LastCellPosition].Text = "1";
                lblIndicator.Text = "0";
            }
        }
    }
    #endregion

    #region Private Methods
    private void populateGridView()
    {
        gvGroup.DataSource = GroupBL.GetGroupList();
        gvGroup.DataBind();
    }

    private void addColumns(GridView newGV, string DataField, string HeaderText, HorizontalAlign Align)
    {
        BoundField bF = new BoundField();
        bF.HeaderText = HeaderText;
        bF.DataField = DataField;
        bF.ItemStyle.HorizontalAlign = Align;
        bF.ItemStyle.CssClass = "gvCell";
        newGV.Columns.Add(bF);
    }

    private void addCheckBoxes(GridView newGV)
    {
        CheckBox cb = new CheckBox();
        TemplateField tf = new TemplateField();
        tf.ItemTemplate =
        tf.ItemStyle.CssClass = "gvCheck";
        newGV.Columns.Add(tf);
    }

    private static DataTable generateTable(List<Member> MemberList)
    {
        DataTable dt = new DataTable();

        //define the columns of the table
        dt.Columns.Add(new DataColumn("ID", typeof(int)));
        dt.Columns.Add(new DataColumn("Name", typeof(string)));
        dt.Columns.Add(new DataColumn("Description", typeof(string)));
        dt.Columns.Add(new DataColumn("Comments", typeof(string)));

        foreach (Member s in MemberList)
        {
            //create a new row
            DataRow dr = dt.NewRow();

            //enter row details
            dr["ID"] = s.ID;
            dr["Name"] = s.Name;
            dr["Description"] = s.Description;
            dr["Comments"] = s.Comments;

            //add the row to the datatable
            dt.Rows.Add(dr);
        }

        return dt;
    }
    #endregion
}

I have no idea how to add a templatefield to the gridview from the code. I need it for the checkboxes.

Any help would be appreciated. Thanks!

You can follow the below steps:
1. Add a template column within the master gridview.
2. Add a collapse image first like <img src="Image/Expand.jpg" onclick="ChildBlock(this,document.getElementById('<%#Eval("ChildID") %>'));" /> which will show hide child details based on user selection by a javascript method.
3. Add a div & give the id=child data id within the template column. Like <div id='<%#Eval("ChildID") %>' style="display:none"> . After that add the child gridview.
4. The childblick javascript method like below:

function ChildBlock(img,obj)
{
if(obj.style.display=='none')
{
obj.style.display='';
img.src="Image/Collapse.jpg";
}
else
{
obj.style.display='none';
img.src="Image/Expand.jpg";
}
}

5. Ok now design is complete. Bind master grid into the page load event & in the RowDataBound method bind child grid in the below way:

if (e.Row.RowType == DataControlRowType.DataRow)
{
DataTable dtProducts = GetProducts(Convert.ToUInt64(((DataRowView)e.Row.DataItem)["ID"]));
((GridView)e.Row.FindControl("gvChild")).DataSource = dtProducts;
((GridView)e.Row.FindControl("gvChild")).DataBind();
}
Member Avatar for nixx

thanks for the link. it doesn't seem to work on browsers other than IE because of the attributes used. I've found something that is sort of what I'm looking for.

http://www.codeproject.com/KB/webforms/EditNestedGridView.aspx

Still trying to figure it out though. Hope it helps others.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.