AspAlliance.com LogoASPAlliance: Articles, reviews, and samples for .NET Developers
URL:
http://aspalliance.com/articleViewer.aspx?aId=660&pId=-1
Multiple Column Sorting and Paging in a DataGrid
page
by souri challa
Feedback
Average Rating: 
Views (Total / Last 10 Days): 55031/ 58

Introduction

 [ Download Code ]

Much has been written about the sorting and paging capabilities of the ASP.NET DataGrid. This article examines bringing together all the aspects of sorting on multiple columns and paging while presenting an easier, intuitive interface.

The goals of the code sample that accompanies this article are to:

  • present an easier way to sort on a combination of DataGrid columns in ascending or descending order;
  • indicate visually the sort direction and sequence number; and 
  • remember the selected sort expression between DataGrid pages.

Before we delve into the code take a look at the screenshot of the DataGrid below.

 


Figure 1: The DataGrid in its final form

 

As you can see, the sort direction is displayed by way of a simple image next to the sorted column in the DataGrid header. The number next to the image represents the sort sequence number for that column. The user can click on any sort-enabled column multiple times to toggle between one of three possible states: ascending, descending, or no sort order. The code sample that accompanies this article also writes the sort expression to the browser's status bar.

DataGrid Declaration and Data Source

 [ Download Code ]

Now let us examine the code in a little detail. The declarative portion of the DataGrid is shown below. Setting the AllowSorting and AllowPaging attributes to true enables the sorting and paging functionality of the DataGrid.

<asp:datagrid id="dgEmployee" runat="server" AllowSorting="True"
AllowPaging="True" AutoGenerateColumns="False"Width="100%"
PageSize="20" Font-Size="10" Font-Name="verdana">
  <AlternatingItemStyle BackColor="#CCCC99"></AlternatingItemStyle>
  <HeaderStyle Font-Bold="True" BackColor="#FFCC00"></HeaderStyle>
     <Columns>
<asp:BoundColumn DataField="FirstName" SortExpression="FirstName"
HeaderText="First Name"></asp:BoundColumn>
<asp:BoundColumn DataField="LastName"  SortExpression="LastName"
HeaderText="Last Name"></asp:BoundColumn>
<asp:BoundColumn DataField="HireDate"  SortExpression="HireDate"
HeaderText="Hire Date"></asp:BoundColumn>
<asp:BoundColumn DataField="Job" SortExpression="Job"
HeaderText="Job Description"></asp:BoundColumn>
<asp:BoundColumn DataField="Publisher"  SortExpression="Publisher"
HeaderText="Publisher"></asp:BoundColumn>
<asp:BoundColumn DataField="City" SortExpression="City"
HeaderText="City"></asp:BoundColumn>
<asp:BoundColumn DataField="State" SortExpression="State"
HeaderText="State"></asp:BoundColumn>
<asp:BoundColumn DataField="Country"
HeaderText="Country"></asp:BoundColumn>
    </Columns>
 <PagerStyle PageButtonCount="20" Mode="NumericPages"></PagerStyle>
</asp:datagrid>
Listing 1

To keep the demonstration simple, the DataGrid is bound to an XML data source, as shown below.

<?xml version="1.0" encoding="utf-8" ?>
<EMPLOYEE>
      <EmpData FirstName="Paolo" LastName="Accorti" HireDate="1992-08-27"
Job="Sales Representative" Publisher="Binnet Hardley" City="Washington"
State="DC" Country="USA" />
      <EmpData FirstName="Pedro" LastName="Afonso" HireDate="1990-12-24"
Job="Designer" Publisher="Algodata Infosystems" City="Berkeley"
State="CA" Country="USA" />
      <EmpData FirstName="Victoria" LastName="Ashworth" HireDate="1990-09-13"
Job="Managing Editor" Publisher="Binnet Hardley" City="Washington"
State="DC" Country="USA" />
</EMPLOYEE>
Listing 2

When a sort expression of a bound column is set, the DataGrid renders the header of the column as a link button. Upon clicking such a link, the DataGrid’s SortCommand event fires and supplies the sort expression as part of the event argument.

Sorting the DataGrid

 [ Download Code ]

The code for the SortCommand event handler is shown below. In a nutshell, the event handler determines a combined sort expression, sets up a DataView on the current data source with that sort expression, and binds the DataGrid to the DataView.

/// <summary>
///  Datagrid Sort Event Handler -> Determine a combined sort expression and apply.
/// </summary>
private void dgEmployee_SortCommand(object source,
System.Web.UI.WebControls.DataGridSortCommandEventArgs e)
{
  DisplaySortedData(GetSortExpression(dgEmployee,e));
}
/// <summary>
///  Apply the Sort Expression to the retrieved data and bind to datagrid
/// </summary>
private void DisplaySortedData(string sortExpression)
      {
            sortExpression = sortExpression.TrimEnd(",".ToCharArray());
            DataSet dsEmployees = new DataSet();
            dsProjects.ReadXml(Server.MapPath("Employee.xml"));
                  
            DataView dvEmployee = new DataView(dsEmployees.Tables[0]);
            dvEmployee.Sort =  sortExpression;
            dgEmployee.DataSource = dvEmployee;
            dgEmployee.DataBind();
      }

Listing 3

The key to implementing the multi-column sorting is to remember the previously clicked sort columns, and to establish the new sort criteria whenever a sort column header is clicked.

In this example the sort expression is persisted between requests in a custom DataGrid attribute named SortExpression. When the page is rendered to the browser this attribute becomes the attribute of the TABLE HTML element and is simply ignored by the browsers.

Another way of persisting the sort expression would be to keep it in a ViewState variable. This method is recommended if the DataGrid itself is not kept in ViewState due to large amounts of data.

Manipulating the Sort Expression

 [ Download Code ]

The GetSortExpression method shown below implements the functionality to evaluate a new sort expression each time a sortable column header is clicked. It starts by examining the custom SortExpression attribute of the DataGrid to see if a previous sort expression exists. If the current sort column exists within this expression, then its sort order is toggled appropriately or the sort column is removed from the sort expression. Otherwise, the sort column is added to the SortExpression attribute.

private string GetSortExpression(DataGrid dg,DataGridSortCommandEventArgs e)
{
      string[] sortColumns = null;
      string sortAttribute = dg.Attributes["SortExpression"];
      //Check to See if we have an existing Sort Order already in the Grid.     
      //If so get the Sort Columns into an array
            if ( sortAttribute != String.Empty)
            {
                  sortColumns = sortAttribute.Split(",".ToCharArray());
            }
      //if User clicked on the columns in the existing sort sequence.
      //Toggle the sort order or remove the column from sort appropriately
            if (sortAttribute.IndexOf(e.SortExpression) > 0 ||
            sortAttribute.StartsWith(e.SortExpression))
            sortAttribute= ModifySortExpression(sortColumns,e.SortExpression);
            else 
            sortAttribute += e.SortExpression+" ASC,";
            dg.Attributes["SortExpression"] = sortAttribute;                 
return sortAttribute;
}
 
private string ModifySortExpression(string[] sortColumns,string sortExpression)
{
            string  ascSortExpression = String.Concat(sortExpression," ASC");
            string  descSortExpression = String.Concat(sortExpression," DESC");    
for (int i=0; i< sortColumns.Length; i++)
      {    
 
            if (ascSortExpression.Equals(sortColumns[i]))
                  {
                        sortColumns[i] = descSortExpression;
                  }
                             
            else if (descSortExpression.Equals(sortColumns[i]))
                  { Array.Clear(sortColumns,i,1);
                  }
            }
             
return
String.Join(",",sortColumns).Replace(",,",",").TrimStart(",".ToCharArray());
       
}
Listing 4

The paging event handler calls upon the same method to display the data in sorted order, after setting up the current page index.

/// <summary>
///  Datagrid Page Changed Event Handler -> Apply the Currently Selected sort expression.
/// </summary>
private void dgEmployee_PageIndexChanged(object source,
System.Web.UI.WebControls.DataGridPageChangedEventArgs e)
{
      dgEmployee.CurrentPageIndex = e.NewPageIndex;
      DisplaySortedData(dgEmployee.Attributes["SortExpression"]);
}
Listing 5
Displaying Sort Direction and Sequence

 [ Download Code ]

One more important aspect of this example is to display the current sorting order in the DataGrid header in a manner that is easy to recognize visually. This is accomplished by inserting an image and number next to the sorted column.

This is implemented in the ItemDataBound event handler of the DataGrid when binding the header item.

private void dgEmployee_ItemDataBound(object sender,
System.Web.UI.WebControls.DataGridItemEventArgs e)
{
  if (e.Item.ItemType == ListItemType.Header)
    {
if (dgEmployee.Attributes["SortExpression"] != String.Empty)
DisplaySortOrderImages(dgEmployee.Attributes["SortExpression"] ,e.Item);
    }       
}
Listing 6

The method DisplaySortOrderImages loops through the cells of the header item. If any of the cells contain a link button, it then looks up its command argument (which is same as that columns sort expression) within the DataGrid’s SortExpression attribute and inserts an image and a literal (for the sequence number) next to the cell.

private void DisplaySortOrderImages(string sortExpression,DataGridItem dgItem)
{       
  string[] sortColumns = sortExpression.Split(",".ToCharArray());
 for (int i=0; i< dgItem.Cells.Count; i++)
 { 
if(dgItem.Cells[i].Controls.Count > 0 && dgItem.Cells[i].Controls[0] is LinkButton)
{
     string sortOrder;
     int sortOrderNo;
     string column = ((LinkButton)dgItem.Cells[i].Controls[0]).CommandArgument;
                    
     SearchSortExpression(sortColumns,column,out sortOrder,out sortOrderNo);
       if (sortOrderNo > 0)
       {
             if (sortOrder.Equals("ASC"))
            {
            Image imgUp = new Image();
            imgUp.ImageUrl = "~/images/sortascending.gif";
            dgItem.Cells[i].Controls.Add(imgUp);
            Literal litOrder = new Literal();
            litOrder.Text = sortOrderNo.ToString();
            dgItem.Cells[i].Controls.Add(litOrder);
            }
            else if (sortOrder.Equals("DESC"))
            {
            Image imgDown = new Image();
            imgDown.ImageUrl = "~/images/sortdescending.gif";
            dgItem.Cells[i].Controls.Add(imgDown);
            Literal litOrder = new Literal();
            litOrder.Text = sortOrderNo.ToString();
            dgItem.Cells[i].Controls.Add(litOrder);
            }
}
 
         }
}
             
 } 





private void SearchSortExpression(string[] sortColumns,string sortColumn,
out string sortOrder,out int sortOrderNo)
{ 
      sortOrder = "";
     sortOrderNo = -1;
for (int i=0; i< sortColumns.Length; i++)
      {
             if (sortColumns[i].StartsWith(sortColumn))
            {
                  sortOrderNo = i+1;
                  sortOrder = sortColumns[i].Substring(sortColumn.Length).Trim();
}
       }
}
Listing 7


Conclusion

To summarize, we've taken advantage of the DataView's sorting capabilities to implement multi-column sorting on the DataGrid. Full source code is included in the downloadable sample. It also shows how to write the sort expression to the browser status bar by registering a client-side Javascript function. Enjoy, and be sure to let me know if you find this article applicable to your project scenario.


Product Spotlight
Product Spotlight 

©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-26 7:47:05 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search