SIGN UP MEMBER LOGIN:    
ARTICLE

GridView Multicolumn sorting

Posted by Nipun Tomar Articles | ASP.NET Controls in C# July 09, 2009
GridView's built-in sorting can be enabled by setting a data source and AllowSorting property to true. Click on column header to sort based on the SortExpression specified in the Gridview column. However, Gridview does not support multi column sorting which is required in day to day application. So here is how I tried to create one:
Reader Level:
Download Files:
 

GridView Multicolumn sorting

The ASP.NET GridView control is the successor to the v1.x DataGrid, adding the ability to take advantage of specific capabilities of ASP.NET data source controls. Whereas the v1.x DataGrid required a page developer to write custom code to handle simple operations such as paging, sorting, editing or deleting data, the GridView control can automatically handle these operations provided its bound data source control supports these capabilities. The GridView also offers some functionality improvements over the DataGrid, such as the ability to define multiple primary key fields, and some UI customization improvements, such as new field types and templating options. It also exposes a new model for page developers to handle or cancel events. Read more..

GridView's built-in sorting can be enabled by setting a data source and AllowSorting property to true. Click on column header to sort based on the SortExpression specified in the Gridview column. However, Gridview does not support multi column sorting which is required in day to day application.

So here is how I tried to create one-

Create a custom control that will inherit from gridview

public class MCNGridView : GridView

Create properties to enable/disable multicolumn sorting

            
bool _ShowSortSequence = false;
        bool _EnableMultiColumnSorting = false;
        string _SortAscImageUrl = string.Empty;
        string _SortDescImageUrl = string.Empty;
        #region Properties
        /// <summary>
        /// Enable/Disable MultiColumn Sorting.
        /// </summary>
        [
        Description("Sorting On more than one column is enabled or not"),
        Category("Behavior"),
        DefaultValue("false"),
        ]
        public bool EnableMultiColumnSorting
        {
            get { return _EnableMultiColumnSorting; }
            set { AllowSorting = true; _EnableMultiColumnSorting = value; }
        }
        /// <summary>
        /// Enable/Disable Sort Sequence visibility.
        /// </summary>
        [
        Description("Show Sort Sequence or not"),
        Category("Behavior"),
        DefaultValue("false"),
        ]
        public bool ShowSortSequence
        {
            get { return _ShowSortSequence; }
            set { _ShowSortSequence = value; }
        }
        /// <summary>
        /// Get/Set Image for displaying Ascending Sort order.
        /// </summary>
        [
        Description("Image to display for Ascending Sort"),
        Category("Misc"),
        Editor("System.Web.UI.Design.UrlEditor", typeof(System.Drawing.Design.UITypeEditor)),
        DefaultValue(""),

        ]
        public string SortAscImageUrl
        {
            get { return _SortAscImageUrl; }
            set { _SortAscImageUrl = value; }
        }
        /// <summary>
        /// Get/Set Image for displaying Descending Sort order.
        /// </summary>
        [
        Description("Image to display for Descending Sort"),
        Category("Misc"),
        Editor("System.Web.UI.Design.UrlEditor", typeof(System.Drawing.Design.UITypeEditor)),
        DefaultValue(""),
        ]
        public string SortDescImageUrl
        {
            get { return _SortDescImageUrl; }
            set { _SortDescImageUrl = value; }
        }

Override Gridview OnSorting event

To get the custom sort expression

protected override void OnSorting(GridViewSortEventArgs e)
        {
            if (EnableMultiColumnSorting)
                e.SortExpression = GetSortExpression(e);
            base.OnSorting(e);
        }

Override Gridview OnRowCreated event

To show the sort direction image and sort sequence

protected override void OnRowCreated(GridViewRowEventArgs e)
        {
            if (e.Row.RowType == DataControlRowType.Header)
            {
                if (SortExpression != String.Empty)
                    ShowSortOrderImages(SortExpression, e.Row);
            }
            base.OnRowCreated(e);
        }


Other protected methods

            
/// <summary>
        ///  Get Sort Expression from existing Grid View Sort Expression
        /// </summary>
        protected string GetSortExpression(GridViewSortEventArgs e)
        {
            string[] sortColumns = null;
            string sortAttribute = SortExpression;
            if (sortAttribute != String.Empty)
            {
                sortColumns = sortAttribute.Split(",".ToCharArray());
            }
            if (sortAttribute.IndexOf(e.SortExpression) > 0 || sortAttribute.StartsWith(e.SortExpression))
                sortAttribute = UpdateSortExpression(sortColumns, e.SortExpression);
            else
                sortAttribute += String.Concat(",", e.SortExpression, " ASC ");
            return sortAttribute.TrimStart(",".ToCharArray()).TrimEnd(",".ToCharArray());

        }
        /// <summary>
        ///  Toggle the sort order or remove the column from sort
        /// </summary>
        protected string UpdateSortExpression(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());
        }
        /// <summary>
        ///  Lookup the Current Sort Expression to determine the Order of a specific item.
        /// </summary>
        protected 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;
                    if (EnableMultiColumnSorting)
                        sortOrder = sortColumns[i].Substring(sortColumn.Length).Trim();
                    else
                        sortOrder = ((SortDirection == SortDirection.Ascending) ? "ASC" : "DESC");
                }
            }
        }
        /// <summary>
        ///  Show an image for the Sort Order with sort sequence no.
        /// </summary>
        protected void ShowSortOrderImages(string sortExpression, GridViewRow 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)
                    {
                        string sortImgLoc = (sortOrder.Equals("ASC") ? SortAscImageUrl : SortDescImageUrl);
 
                        if (sortImgLoc != String.Empty)
                        {
                            Image imgSortDirection = new Image();
                            imgSortDirection.ImageUrl = sortImgLoc;
                            dgItem.Cells[i].Controls.Add(imgSortDirection);
                            if (EnableMultiColumnSorting && _ShowSortSequence)
                            {
                                Label lblSortOrder = new Label();
                                lblSortOrder.Font.Size = FontUnit.XSmall;
                                lblSortOrder.Font.Name = "verdana";
                                lblSortOrder.Text = sortOrderNo.ToString();
                                dgItem.Cells[i].Controls.Add(lblSortOrder);
                            }
                        }
                        else
                        {
                            Label lblSortDirection = new Label();
                            lblSortDirection.Font.Size = FontUnit.XSmall;
                            lblSortDirection.Font.Name = "verdana";
                            lblSortDirection.EnableTheming = false;
                            lblSortDirection.Text = (sortOrder.Equals("ASC") ? "^" : "v");
                            dgItem.Cells[i].Controls.Add(lblSortDirection);
                            if (EnableMultiColumnSorting && _ShowSortSequence)
                            {
                                Literal litSortSeq = new Literal();
                                litSortSeq.Text = sortOrderNo.ToString();
                                dgItem.Cells[i].Controls.Add(litSortSeq);
                            }
                        }
                    }
                }
            }
        }

On Aspx page

Register the control

<%@ Register Assembly="MCNGridView" namespace="MCNGridView" tagprefix="MCN" %>

Create the grid and bind the data

<MCN:MCNGridView ID="MCNGridView1" runat="server" EnableMultiColumnSorting="True"       
        AutoGenerateColumns="False" DataKeyNames="CustomerID"  ShowSortSequence="True"
        DataSourceID="SqlDataSource1" CellPadding="4"
        ForeColor="#333333" GridLines="None" AllowPaging="True"
        SortAscImageUrl="~/Images/asc.png" SortDescImageUrl="~/Images/desc.png">
        <RowStyle BackColor="#EFF3FB" />
        <Columns>
            <asp:BoundField DataField="CustomerID" HeaderText="CustomerID" ReadOnly="True"
                SortExpression="CustomerID">
            </asp:BoundField>
            <asp:BoundField DataField="CompanyName" HeaderText="CompanyName"
                SortExpression="CompanyName" />
            <asp:BoundField DataField="ContactName" HeaderText="ContactName"
                SortExpression="ContactName" />
            <asp:BoundField DataField="ContactTitle" HeaderText="ContactTitle"
                SortExpression="ContactTitle" />
            <asp:BoundField DataField="City" HeaderText="City" SortExpression="City" />
            <asp:BoundField DataField="Region" HeaderText="Region"
                SortExpression="Region" />
            <asp:BoundField DataField="PostalCode" HeaderText="PostalCode"
                SortExpression="PostalCode" />
            <asp:BoundField DataField="Country" HeaderText="Country"
                SortExpression="Country" />
        </Columns>
        <FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
        <PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
        <SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
        <HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
        <EditRowStyle BackColor="#2461BF" />
        <AlternatingRowStyle BackColor="White" />
    </MCN:MCNGridView>

Thats all you are ready with Multicolumn sorting in Gridview.

Login to add your contents and source code to this article
share this article :
post comment
 

I am trying your code by using dataset. On page load it displays the data properly and when we click on any field for sorting, it gives the exception "The GridView 'MCNGridView1' fired event Sorting which wasn't handled." Why it is happening so.

Posted by Muhammad Shariq Khan Jul 20, 2010

Best for those who are looking for extending GridView.

Posted by adil umair Oct 19, 2009

Looks great, but I can only get it to filter 1 column, the others don't change when the filters are applied.  Any thoughts on what I'm doing wrong?

Posted by STEVE PEGG Sep 22, 2009
Become a Sponsor
PREMIUM SPONSORS
  • Get 2 Months Free of ASP.NET Hosting for Only $4.95/month! Receive FREE MS SQL and MySQL Databases Including ASP.NET 4/3.5, MVC 3.0, Silverlight 4, Windows 2008/IIS 7.0 Plus FREE IIS 7 Modules. Host UNLIMITED ASP.NET Web Sites - Click Here!
    Get 2 Months Free of ASP.NET Hosting for Only $4.95/month! Receive FREE MS SQL and MySQL Databases Including ASP.NET 4/3.5, MVC 3.0, Silverlight 4, Windows 2008/IIS 7.0 Plus FREE IIS 7 Modules. Host UNLIMITED ASP.NET Web Sites - Click Here!
Become a Sponsor