Link to home
Start Free TrialLog in
Avatar of Fraser_Admin
Fraser_AdminFlag for Canada

asked on

Details on gridview

I have a master detail relationship on my tables.  I would like to show the master record in the gridview, then allow the user to click on a + to see details.

When expanded it should look like this.  I also want to give the user an option to say expand all so they can see all the detail for all records.

How is this accomplished?

Master 1 Record
   Detail 1-1 Record
   Detail 1-2 Record
   Detail 1-3 Record
Master 2 Record
   Detail 2-1 Record
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

That sounds like nested controls in a GridView.

Walkthrough: Creating a Nested GridView Control  
http://msdn.microsoft.com/en-us/library/aa992038(VS.80).aspx

You can nest different inner controls, on a GridViewRow, such as a GridView, DataList, Repeater, ListView, etc.
Use a nested Gridview inside an ajax collapsiblepanelextender.
Avatar of Fraser_Admin

ASKER

will it only show records when you want.  i want to default the main grid to not show detail records by default, then allow the user to choose to view the details (with a +/- to show/hide).

also i would like the user to be able to indicate that they want to see all the details.  can this be done?
what are the benfits to using an ajax collapsiblepanelextender?
The CollapsiblePanelExtender will give you the ability to show/hide the nested controls within each row.  The records that you show in the detail are completely up to you, since that control will need its own data source.
I have placed my gridview in a panel and refer to that panel in my collapsiblepanelextender.  i have the it should intially not show.  but when the page loads you can briefly see all the detail and then it goes away.  is there a way to not see that detail at all when the page initially loads?
could ajax be used to only fetch the details when requested?
ok figured out the flashing part.

one other question, is there a way to have the other column items display at the top and not centered in the row when the nested gridview shows?

example it is doing this


                   detail 1
                   detail 2
                   detail 3
master 1     detail 4   master 1 other
                   detail 5
                   detail 6
I don't understand that layout problem.  The GridView normally displays data in columns, so that problem looks more like a DetailsView than a GridView...
no it is a gridview.  the whole thing i'm showing is one row.  all the details are the nested gridview.  the other columns, instead of it putting the values at the top of the row, it is showing them in the middle.
found it...ItemStyle-VerticalAlign ="Top"

so the only unanswered part of my question is there someway the clicking of the title panel be captured in code behind, and only then call the routine to show the details to enhance performance?
If you change the GridView to a Repeater, you would have more control over the layout, with HTML tables.  I have attached an example of what I mean.

Default.aspx


<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default.aspx.vb" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Nested Repeater Example</title>
</head>
<body>
  <form id="form1" runat="server">
  <div>
    <asp:ScriptManager ID="ScriptManager1" runat="server" />
    <asp:Repeater ID="ProductRepeater" runat="server" OnItemDataBound="ProductRepeater_ItemDataBound">
      <HeaderTemplate>
        <table border="1" cellpadding="0" cellspacing="0" style="font-family: Tahoma; font-size: medium;">
      </HeaderTemplate>
      <ItemTemplate>
        <tr>
          <td colspan="2">
            <asp:Label ID="ProductCategoryLabel" runat="server" Text='<%# Eval("Name") %>' ForeColor="White" BackColor="SteelBlue" Width="100%" />
          </td>
        </tr>
        <tr>
          <td style="width: 50px;">
            &nbsp;
          </td>
          <td>
            <asp:Repeater ID="SubCategoryRepeater" runat="server" OnItemDataBound="SubCategoryRepeater_ItemDataBound">
              <HeaderTemplate>
                <table border="0" cellpadding="0" cellspacing="0" style="font-family: Tahoma; font-size: medium;">
              </HeaderTemplate>
              <ItemTemplate>
                <tr>
                  <td colspan="2">
                    <asp:Label ID="ProductSubCategoryLabel" runat="server" Text='<%# Eval("Name") %>' ForeColor="Purple" Width="100%" Font-Underline="true" />
                  </td>
                </tr>
                <tr>
                <td style="width: 50px;">
                  &nbsp;
                </td>
                <td style="font-size: small;">
                  <asp:Panel ID="ProductCollapsiblePanel" runat="server">
                    <asp:Repeater ID="ProductRepeater" runat="server">
                      <HeaderTemplate>
                        <table border="0" cellpadding="0" cellspacing="0" style="font-family: Tahoma; font-size: small;">
                      </HeaderTemplate>
                      <ItemTemplate>
                        <tr>
                          <td>
                            <asp:Label ID="ProductLabel" runat="server" Text='<%# Eval("Name") %>' Width="100%" />
                          </td>
                        </tr>
                      </ItemTemplate>
                      <FooterTemplate>
                        </table>
                      </FooterTemplate>
                    </asp:Repeater>
                  </asp:Panel>             
                </td>
                </tr>
              </ItemTemplate>
              <FooterTemplate>
                </table>
              </FooterTemplate>
            </asp:Repeater>
          </td>
        </tr>
      </ItemTemplate>
      <FooterTemplate>
        </table>
      </FooterTemplate>
    </asp:Repeater>
  </div>
  </form>
</body>
</html>

Open in new window

Default.aspx.vb:


Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Web.UI.WebControls

Partial Class _Default
    Inherits System.Web.UI.Page

    Private _dataContext As AdventureWorksDataContext

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
        _dataContext = New AdventureWorksDataContext()

        If Not Me.Page.IsPostBack Then
            Me.BindProductRepeater()
        End If
    End Sub

    Private Sub BindProductRepeater()
        Dim q = From p In _dataContext.Products _
            Join s In _dataContext.ProductSubcategories On p.ProductSubcategoryID Equals s.ProductSubcategoryID _
            Join c In _dataContext.ProductCategories On s.ProductCategoryID Equals c.ProductCategoryID _
            Group c By Key = c.Name Into Group _
            Select Category = Group.First()

        Dim productList As List(Of ProductCategory) = q.ToList()

        Me.ProductRepeater.DataSource = productList
        Me.ProductRepeater.DataBind()
    End Sub

    Protected Sub ProductRepeater_ItemDataBound(ByVal sender As Object, ByVal e As RepeaterItemEventArgs)
        If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem Then
            Dim category As ProductCategory = TryCast(e.Item.DataItem, ProductCategory)

            Dim subCategoryRepeater As Repeater = TryCast(e.Item.FindControl("SubCategoryRepeater"), Repeater)

            subCategoryRepeater.DataSource = category.ProductSubcategories
            subCategoryRepeater.DataBind()
        End If
    End Sub

    Protected Sub SubCategoryRepeater_ItemDataBound(ByVal sender As Object, ByVal e As RepeaterItemEventArgs)
        If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem Then
            Dim subCategory As ProductSubcategory = TryCast(e.Item.DataItem, ProductSubcategory)

            Dim productRepeater As Repeater = TryCast(e.Item.FindControl("ProductRepeater"), Repeater)

            productRepeater.DataSource = subCategory.Products
            productRepeater.DataBind()
        End If
    End Sub

End Class

Open in new window

LINQ-to-SQL DataContext to the SQL Server AdventureWorks database:


Screenshot.png
Rendered output:


Screenshot.png
how do i only select details when the user wants to see them though?
I didn't take the time to put in a collapsible panel, but you could use that to collapse the details.  I did wrap the ProductRepeater with a Panel (ProductCollapsiblePanel), that you can link to a CollapsiblePanelExtender.
no what i don't like about the collapsible panel is that it loads all the details (which is lengthy), i only want the deatils to load when a user requests it.  unless i'm missing something, it looks as if it loads everything.
You don't have to use a CollapsiblePanelExtender, that was only one suggestion.  And, you don't need to load all the data when the page is first load.  That example that I showed you was just to show how the Repeater can be used to control the layout with rows and cells.  

Another possibility is to use a HyperLink with a collapse and expand images that can use client-side code (AJAX) to call a code-behind method to build the child <div> that contains the details.
so how would i go about that.  my gridview is working fine.  so would i wrap that in an updatepanel.  and somehow capture the click event of the image to toggle if i bind and show the grid, then change the image to the collapse?
ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial