Customize the sorting header with "up-down" arrow effect when sorting with ListView

ListView is absolutely a great template-enabled DataBoundControl , for that it renders client side code entirely basing on user-defined layout template , where itemTemplate can also be freely designed in "unlimited" html manner than a drab "table cell". Although GridView may lessen you code in common "records displaying" cases , you may feel uncomfortably restricted by its rigid displaying style ( each record must be displayed in the manner of "a row of a table" ) when intending to control the html output codes thoroughlly. At least , as for me ------I hate the nonsense auto-produced code of GridView.

What's more, ListView brings an exciting convenience of sound data management. Traditional useful DataBoundControls, such as GridView and FormView, each has its natural defect when facing data operations: GridView lacks the ability of inserting a single record directly while FormView cannot supply a multiple-records-view. In asp.net 2.0 you must combine them to produce a sound "data malnipulation" solution. Now ListView's "InsertItem" add-in is designed to support the "CRUD-just-in-One-control" case.

Since ListView is so cool ,let's improve its data operation function details to make it better~ As for a sorting-enabled DataBoundControl , it is a common requirement to add symbol indicating current sorting information ( which field && which direction ) . If searching internet you may find several good articles expositing how to add the feature to a plain GridView header shown as follows:

The second article introduces a "CSS-based" UI handling instead of img-alternating control . I approve it because in today's web-design-world , "managing UI with structrured CSS as much as possible" is an advanced conception and a golden rule. Now since I strongly recommanded ListView for table-displaying , I will provide a "CSS-based" sorting-header handling solution dealing with ListView ,which resembles that of GridView but differs slightly.

In the begining let's make out which context is the "right" place to handle sort-header apperance. From MSDN .NET REFERENCE you can find an "arrow-featured" sorting UI solution in the sample of ListView.OnSorting section , which I think reveal that Microsoft officially approve a way of handling sort-header UI in such event-context. Although some other articles put the task in "DataBound" event and it is practictable , I prefer OnSorting for the reason that many command-trigger may cause the "DataBound" event such as Edit/Update/Paging and first page-loading and they are irrelevant to "Sorting" behavior ; The sorting header outlook will not change after these operations so handling header-UI each time DataBinding may diminish the whole performance generally. When focusing on "OnSorting" event we ensure the neccessary of header-handling work.

Then I will use some code to explain my approach. Note : this is not an "ABC" tutorial , I do not intend to explain details step by step ; instead , I just show two key steps of implementing such sorting function in a ListView:

First , since the record list is a traditional html table , a "table-layout" should be initialized in the "LayoutTemplate":

<LayoutTemplate>
            <table>
                <tr runat="server" id="headerRow">
                    <th runat="server">
                        <asp:LinkButton runat="server" ID="btnName" CommandArgument="Name" CommandName="Sort"
                            Text="Name"></asp:LinkButton>
                    </th>
                    <th runat="server">
                        <asp:LinkButton runat="server" ID="btnAge" CommandArgument="Age" CommandName="Sort"
                            Text="Age"></asp:LinkButton>
                    </th>
                    <th runat="server">
                        <asp:LinkButton runat="server" ID="btnCreatedOn" CommandArgument="CreatedOn" CommandName="Sort"
                            Text="Created On"></asp:LinkButton>
                    </th>
                    <th>
                        Details
                    </th>
                </tr>
                <tr id="itemRow" runat="server">
                </tr>
            </table>
        </LayoutTemplate>

Note that the "header row" ( tr ) must be tagged as a "server html control" , the same as the "cells" belonging to header row and containing a "sort button" ( eg . the "Details" header need not sorting then it is not marked as "server html control" ) . We need access and control the sorting cell programably.

The next crux is attaching Sorting event to certain concret handler. Please see the code segment with my comment.

 //  such code seg can serve as a common event handler of ListViews that need sorting function..
    protected void commonList_Sorting(object sender, ListViewSortEventArgs e)
    {
        Control me = (Control)sender,
           headerRow = me.FindControl("headerRow");

        /*
         we assume that the "header row" control's "control collection" just contains "th"-like control,
         whose type is exactly "HtmlTableCell" . While we just utilize its properties in the "HtmlControl" level
         so we cast them as "HtmlControl"

         What's more , as for these "th" controls , just those who contains an "IButtonControl" ( sorting triggers)
         are really needed.
        */
      
        foreach (HtmlControl sortCell in headerRow.Controls.Cast<HtmlControl>()
            .Where( th => th.Controls.OfType<IButtonControl>().Any()  ) )
        {
           /*
             get out the "only" sorting-Button Control ,
             for that in a "th" those empty space or literal text area are treated as "Literal Control" ,
             "literal" fills whole space of "th" just like air abounds a room..
           */
            IButtonControl btnSortField = sortCell.Controls.OfType<IButtonControl>().Single();

            if (btnSortField.CommandArgument == e.SortExpression)
                sortCell.Attributes["class"] = e.SortDirection == SortDirection.Ascending ? "up" : "down";
            else
                if( sortCell.Attributes["class"] != null ) sortCell.Attributes.Remove("class");
        }

    }

OK... That's the key points of my solution. You can see its effect from snapshot picture. I also provide a sample code zip file and expect it to be help of your project.

6 Comments

Comments have been disabled for this content.