Nested Editable Grid view with on demand data binding

6

February 10, 2009 by temebele

Everything is hierarchical in nature

In life, there is always a master detail relationship.

Often, UI developers are expected to build an interface that represents a hierarchical relationship.

Users always ask for flexibility to be able to control things in a higher level and drill down to detail only when they have to.

If you are ASP.NET developer, you can build this relationship easily using Nested Grid View.

Though not the complete source code, I am sharing snippets of codes and mark up that is good enough to help you answer some questions that you may have when building nested grid view. If you have questions just add comments and I will try to answer your questions.

Grid view (HTML markup)

Create your nested grid view inside the last template filed of your master grid. Put in a div container and set it’s style to display none. You also need to modify the table cell holding this grid to span the whole row so that it looks like it is tree like data. Below is excerpt out of the master-detail nested grid (I have highlighted the parts that are most important to you.)

        <asp:GridView ID=”LanesGrid” runat=”server” OnDataBound=”RowDataBound” AutoGenerateColumns=”false”
            AllowPaging=”true” AllowSorting=”true” CssClass=”datatable” CellPadding=”0″”
            CellSpacing=”0″” BorderWidth=”0″” GridLines=”None” OnRowDataBound=”LanesGrid_RowDataBound”
            OnSorting=”LanesGrid_OnSorting” ShowFooter=”true” PageSize=”10″” OnRowCancelingEdit=”LanesGrid_RowCancellingEdit”
            OnRowEditing=”LanesGrid_RowEditing” OnRowDeleting=”LanesGrid_RowDeleting” OnRowUpdating=”LanesGrid_RowUpdating”
            OnRowCommand=”LanesGrid_RowCommand”>
            <PagerStyle CssClass=”pager-row” />
            <RowStyle CssClass=”row” />
            <Columns>
                <asp:TemplateField>
                    <ItemTemplate>
                        <asp:ImageButton runat=”server” ID=”ExpandNestedGridButton” CommandName=”ExpandNestedGrid”
                            ImageUrl=”~/Content/images/icon_plus_gray.gif” CommandArgument=”<%# Container.DataItemIndex %> />
                    </ItemTemplate>
                    <FooterTemplate>
                        <asp:LinkButton ID=”PreviousPageLink” runat=”server” CommandArgument=”Prev” CommandName=”Page”
                            CssClass=”PagerLinkPrev” OnClick=”PagePrevClick”>

Prev <%= PagePrevCount %>

                        </asp:LinkButton>
                        <asp:Label runat=”server” ID=”PageCounterLabel” Text=”1-10 of 400″” />
                        <asp:LinkButton ID=”NextPageLink” runat=”server” CommandArgument=”Next” CommandName=”Page”
                            CssClass=”PagerLinkNext” OnClick=”PageNextClick”>

Next <%= PageNextCount %>

                        </asp:LinkButton>
                    </FooterTemplate>
                </asp:TemplateField>
                <asp:TemplateField HeaderStyle-CssClass=”first” ItemStyle-CssClass=”first” HeaderText=”From country”
                    SortExpression=”FROM_COUNTRY”>
                    <ItemTemplate>
                        <asp:HiddenField ID=”FromCountryHiddenField” runat=”server” Value=’’<%# Eval(“FromCountryID”)%>’’ />
                        <asp:HiddenField ID=”LaneHiddenField” runat=”server” Value=’’<%# Eval(“LANE_ID”)%>’’ />
                        <asp:Label Text=’’<%# Eval(“FROM_COUNTRY”)%>’’ runat=”server” ID=”FromCountryLabel” />
                    </ItemTemplate>
                    <EditItemTemplate>
                        <asp:Label Text=’’<%# Eval(“FROM_COUNTRY”)%>’’ runat=”server” ID=”FromCountryLabel2″” />
                        <asp:HiddenField ID=”FromCountryHiddenFieldEdit” runat=”server” Value=’’<%# Eval(“FromCountryID”)%>’’ />
                    </EditItemTemplate>
                </asp:TemplateField>
                <asp:CommandField ShowEditButton=”True” />
                <asp:CommandField ShowDeleteButton=”true” />
                <asp:TemplateField>
                    <ItemTemplate>
                        </td></tr>
                        <tr>
                            <td colspan=”100%” class=”NestedGridCell”>
                                <div id=”ContainerDiv” style=”display: none; position: relative; left: 25px; runat=”server”>
                                    <asp:GridView ID=”LanesNestedGrid” runat=”server” Width=”80%” AutoGenerateColumns=”false”
                                        EmptyDataText=”No data.” CssClass=”datatable” AllowSorting=”true” GridLines=”None”
                                        DataKeyNames=”LANE_ID” OnRowCommand=”LanesNestedGrid_RowCommand”>
                                        <HeaderStyle />
                                        <RowStyle CssClass=”row” />
                                        <Columns>
                                            <asp:TemplateField HeaderStyle-CssClass=”first” ItemStyle-CssClass=”first” HeaderText=”From country”
                                                SortExpression=”FROM_COUNTRY”>
                                                <ItemTemplate>
                                                    <asp:Label Text=’’<%# Eval(“FROM_COUNTRY”)%>’’ runat=”server” ID=”NestedFromCountryLabel” />
                                                    <asp:HiddenField ID=”NestedFromCountryHiddenLabel” runat=”server” Value=’’<%# Eval(“FromCountryID”)%>’’ />
                                                </ItemTemplate>
                                                <EditItemTemplate>
                                                    <asp:HiddenField ID=”NestedFromCountryHiddenLabelEdit” runat=”server” Value=’’<%# Eval(“FromCountryID”)%>’’ />
                                                    <asp:Label Text=’’<%# Eval(“FROM_COUNTRY”)%>’’ runat=”server” ID=”NestedFromCountryLabel2″” />
                                                </EditItemTemplate>
                                            </asp:TemplateField>
                                            <asp:TemplateField>
                                                <ItemTemplate>
                                                    <asp:LinkButton runat=”server” ID=”EditRowCommandButton” Text=”Edit” CommandName=”EditRow”
                                                        CommandArgument=”<%# Container.DataItemIndex %> />
                                                    <asp:LinkButton runat=”server” ID=”DeleteRowCommandButton” Text=”Delete” CommandName=”DeleteRow”
                                                        CommandArgument=”<%# Container.DataItemIndex %> />
                                                </ItemTemplate>
                                                <EditItemTemplate>
                                                    <asp:LinkButton runat=”server” ID=”UpdateRowCommandButton” Text=”Update” CommandName=”UpdateRow”
                                                        CommandArgument=”<%# Container.DataItemIndex %> />
                                                    <asp:LinkButton runat=”server” ID=”CancelEditCommandButton” Text=”Cancel” CommandName=”CancelRow”
                                                        CommandArgument=”<%# Container.DataItemIndex %> />
                                                </EditItemTemplate>
                                            </asp:TemplateField>
                                        </Columns>
                                    </asp:GridView>
                                </div>
                            </td>
                        </tr>
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>
        </asp:GridView>

Expanding Nested Grid

I have seen implementation on the interent where people bind both the master and detail grid and then hide and show the nested grid pane using javascript. That implementation will work for small data.

But in most cases where we are pulling a big data,  our nested grid should be smart enough to load the child(detail) data only on demand.

– You expand the nested grid on a master grid row command.

   /// <summary>
    /// Expanding back nested Grid
    /// </summary>
    /// <param name=”sender”></param>
    /// <param name=”args”></param>
    /// Row command used for multiple purposes
    protected void LanesGrid_RowCommand(object sender, GridViewCommandEventArgs args)

    {
        var gv = (GridView) sender;

        int rowNumber = -1;

        Int32.TryParse(args.CommandArgument.ToString(), out rowNumber);

        GridViewRow row = gv.Rows[rowNumber];

        if (args.CommandName == “ExpandNestedGrid”)

        {
            var nestedGrid = row.FindControl(“LanesNestedGrid”) as GridView;

            var containerDiv = row.FindControl(“ContainerDiv”) as HtmlControl;

            var expandButton = row.FindControl(“ExpandNestedGridButton”) as ImageButton;

            if (expandButton != null && expandButton.ImageUrl.IndexOf(“icon_x_gray”) != -1)

            {
                expandButton.ImageUrl = expandButton.ImageUrl.Replace(“icon_x_gray”, “icon_plus_gray”);

                OpenedDivsHiddenField.Value = “”;

                containerDiv.Style.Add(HtmlTextWriterStyle.Display, “none”);
            }

            else if (expandButton != null && expandButton.ImageUrl.IndexOf(“icon_plus_gray”) != -1)

            {
                expandButton.ImageUrl = expandButton.ImageUrl.Replace(“icon_plus_gray”, “icon_x_gray”);

                BindNestedZonesGrid(nestedGrid, fromCountryID, toCountryID);

                containerDiv.Style.Add(HtmlTextWriterStyle.Display, “inline”);

                OpenedDivsHiddenField.Value = containerDiv.ClientID;
            }
        }
    }

Re-expanding Nested Grid on PostBack

If a postback happens from within the nested grid view, we want to expand that nested grid after the postback happens. You can track that with view state and then on a row command of the nested grid, you can inject a javascript to show the panel.

On Page load:

if (Request[StringConstants.EventTarget] != null)
        {
            string strEventTarget = Request[StringConstants.EventTarget].ToLower();
            if (strEventTarget.IndexOf(“lanesnestedgrid”) != -1)
            {
                ViewState[“Mode”] = FQ.CarrierRatesManagement.Web.Helper.StringConstants.Expand;
            }
        }

On Row Command

  string openedDivIDs = OpenedDivsHiddenField.Value;
        if (ViewState[“Mode”] != null && ViewState[“Mode”].ToString() == StringConstants.Expand)
        {
            if (!string.IsNullOrEmpty(openedDivIDs))
            {
                string script = “var x = document.getElementById(‘” + openedDivIDs +
                                “‘);if(x){x.style.display = ‘inline’;}”;
                Page.ClientScript.RegisterStartupScript(GetType(), “ExpandNestedGrid”, script, true);
            }
        }

 

Note: For edits and deletes inside the nested grid view, try to use row command. Using the default Edit and delete command fields will have problems if you are binding the nested grid data on demand.

If I have saved you some development time, if this article was relevant to you or if you have any questions add comments and I will try to reply.

Thanks

6 thoughts on “Nested Editable Grid view with on demand data binding

  1. chris says:

    would you have the source code available?

  2. Durga Prasad.A says:

    It is very good Article.It helps me a lot.

  3. temebele says:

    I’m glad it helped.

  4. Sandhya M. Potdar says:

    It helps me, Thanks a lot!

  5. I like ur blog on nested editable grid view.I think this helps us a lot in easily adding or editing data in databases.for more information on .net grid visit on
    http://dapfor.com/en/net-suite/net-grid/features

  6. mkufer says:

    Could you please explain what objects are behind:

    StringConstants.EventTarget
    and
    FQ.CarrierRatesManagement.Web.Helper.StringConstants.Expand

    And how these object are declared?

    Thank You
    Martin

Leave a comment