DNR
DNR

Reputation: 3736

Displaying records grouped by month and year in asp.net

I need to sort my records by date (month & year) as displayed on my asp.net page;
Any ideas / suggestions would be helpful.

This is the code I currently have

                <table width="40%" border="0" style="margin-left:auto; margin-right:auto;">
                    <tr><td><asp:Label ID="lblGridHeader" CssClass="TextFont" Text="" runat="server"></asp:Label></td></tr>
                    <tr>
                        <td align="center">
                            <asp:GridView ID="gvInvoiceList" runat="server" AutoGenerateColumns="false" AllowSorting="true">
                                <columns>
                                    <asp:TemplateField ItemStyle-Width="10%" HeaderText="File Type">
                                        <ItemTemplate><asp:HyperLink ID="imgFileType" ImageUrl="images/Icon_Pdf.gif" NavigateUrl='<%# SetNavigateUrl(Eval("Name")) %>' runat="server"></asp:HyperLink></ItemTemplate>
                                    </asp:TemplateField>
                                  <asp:boundfield datafield="Name" headertext="Invoice #"/>
                                  <asp:boundfield datafield="LastWriteTime" headertext="Date Modified"/>
                                </columns>
                            </asp:GridView>
                        </td>
                    </tr>
                </table>

Code behind:

    If files.Count > 0 Then
        Dim DT As New DataTable()
        DT.Columns.Add(New DataColumn("Name", System.Type.GetType("System.String")))
        DT.Columns.Add(New DataColumn("LastWriteTime", System.Type.GetType("System.String")))

        Dim strCurrentMonth As String = ""

        For Each f As FileInfo In files
            If (MonthName(f.LastWriteTime.Month) <> strCurrentMonth) And (strCurrentMonth <> "") Then
                gvInvoiceList.DataSource = DT
                gvInvoiceList.DataBind()

                lblGridHeader.Text = MonthName(f.LastWriteTime.Month) & " - " & Year(f.LastWriteTime)
            Else
                lblGridHeader.Text = MonthName(f.LastWriteTime.Month) & " - " & Year(f.LastWriteTime)
            End If

            Dim Row1 As DataRow
            Row1 = DT.NewRow()
            Row1("Name") = f.Name
            Row1("LastWriteTime") = f.LastWriteTime
            DT.Rows.Add(Row1)

            strCurrentMonth = MonthName(f.LastWriteTime.Month)
        Next
        gvInvoiceList.DataSource = DT
        gvInvoiceList.DataBind()
    Else
        lblSummary.Text = "No data to show."
    End If  

Upvotes: 2

Views: 4870

Answers (2)

Amry
Amry

Reputation: 4971

The ASP.NET content that you have should be put in a Repeater. The files that you have should then be grouped by the month and date. So basically you will end up with a parent-child list. The parent which is the group of files will be bound to the Repeater, and the children which are the files belonging to that group will be bound the the GridView in the Repeater.


The ASP.NET content

The ASP.NET content would be something along this line. Take note the gvInvoiceList DataSource property is bound to InvoiceList, a property of the group that I came up with (which you will see in the code below) that will have a list of files belonging to the group.

<asp:Repeater ID="repInvoiceGroups" runat="server">
    <ItemTemplate>
        <table width="40%" border="0" style="margin-left:auto; margin-right:auto;">
            <tr><td><asp:Label ID="lblGridHeader" CssClass="TextFont" 
                               Text='<%# Eval("MonthYear", "{0:MMMM yyyy}") %>' 
                               runat="server"></asp:Label></td></tr>
            <tr>
                <td align="center">
                    <asp:GridView ID="gvInvoiceList" runat="server" 
                                  AutoGenerateColumns="false" AllowSorting="true" 
                                  DataSource='<%# Eval("InvoiceList") %>'>
                        <columns>
                            <asp:TemplateField ItemStyle-Width="10%" HeaderText="File Type">
                                <ItemTemplate><asp:HyperLink ID="imgFileType" ImageUrl="images/Icon_Pdf.gif" NavigateUrl='<%# SetNavigateUrl(Eval("Name")) %>' runat="server"></asp:HyperLink></ItemTemplate>
                            </asp:TemplateField>
                          <asp:boundfield datafield="Name" headertext="Invoice #"/>
                          <asp:boundfield datafield="LastWriteTime" headertext="Date Modified"/>
                        </columns>
                    </asp:GridView>
                </td>
            </tr>
        </table>
    </ItemTemplate>
</asp:Repeater>


The code-behind

As for the code, I'm not fluent on using DataTable to have the parent-child relationship needed for the ASP.NET structure that I used for my answer, but it should be easily doable using normal classes. And I'm also not fluent on using VB.NET, so excuse my example which will be using C#, which I guess you should able to convert it quite easily to VB.NET.

I'm using Linq to do the grouping and an anonymous class to have the parent-child relationship for this, so the code is rather short.

repInvoiceGroups.DataSource = files
    .GroupBy(f => f.LastWriteTime.ToString("yyyy-MM"))
    .Select(g => new { 
        MonthYear = DateTime.ParseExact(g.Key, "yyyy-MM", CultureInfo.InvariantCulture), 
        InvoiceList = g.OrderByDescending(f => f.LastWriteTime) })
    .OrderByDescending(o => o.MonthYear);
repInvoiceGroups.DataBind();


p/s: The code was written in a text editor and untested. Let me know if you face any errors. :)

Upvotes: 0

Icarus
Icarus

Reputation: 63966

You can do this with a Repeater. Something like this (you should be able to adapt it easily):

<asp:Repeater ID="rpt" runat="server" OnItemDataBound="rpt_RowDataBound">
        <ItemTemplate>
            <table runat="server" style="color: White; background-color: #3A4F63;" visible="false"
                id="headerTable">
                <tr>
                    <td colspan="3">
                        <asp:Label ID="headerTitle" runat="server"></asp:Label>
                    </td>
                </tr>
                <tr>
                    <td style="width: 200px; background-color: #3A4F63; color: White;">
                        Name
                    </td>
                    <td style="width: 200px;">
                        Directory Name
                    </td>
                    <td style="width: 200px;">
                        Creation Time
                    </td>
                </tr>
            </table>
            <!-- These are the actual data items -->
            <!-- Bind to your specific properties i.e. Invoice #, file type, etc. -->
            <table>
                <tr>
                    <td style="width: 200px;">
                        <asp:Label ID="lblName" runat="server" Text='<%#Eval("Name") %>'></asp:Label>
                    </td>
                    <td style="width: 200px;">
                        <asp:Label ID="lblDirName" runat="server" Text='<%#Eval("DirectoryName") %>'></asp:Label>
                    </td>
                    <td style="width: 200px;">
                        <asp:Label ID="lblCreationTime" runat="server" Text='<%#Eval("CreationTime") %>'></asp:Label>
                    </td>
                </tr>
            </table>
        </ItemTemplate>
    </asp:Repeater>

On Code Behind, the OnItemDataBound looks like this:

Private month As Integer = -1
Private year As Integer = -1
Protected Sub rpt_RowDataBound(sender As Object, e As RepeaterItemEventArgs)

    If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem Then
    'Binding to FileInfo objects. You are binding to DataTable. Adjust it accordingly
        If month <> TryCast(e.Item.DataItem, FileInfo).CreationTime.Month OrElse year <> TryCast(e.Item.DataItem, FileInfo).CreationTime.Year Then
            month = TryCast(e.Item.DataItem, FileInfo).CreationTime.Month
            year = TryCast(e.Item.DataItem, FileInfo).CreationTime.Year
            e.Item.FindControl("headerTable").Visible = True
            TryCast(e.Item.FindControl("headerTitle"), Label).Text = "Files for " & TryCast(e.Item.DataItem, FileInfo).CreationTime.ToShortDateString()
        Else
            e.Item.FindControl("headerTable").Visible = False
        End If
    End If
End Sub

The way I bound my data to the repeater is like this:

Dim fi As FileInfo() = New DirectoryInfo("C:\").GetFiles().OrderByDescending(Function(x) x.CreationTime).ToArray()
rpt.DataSource = fi
rpt.DataBind()

Produces this output:

enter image description here

Upvotes: 3

Related Questions