This was asked to me lot of times but I couldn’t find a better way of doing it hence did not write. Few days back I noticed that a plug in is available for jQuery that can sort HTML tables Thus I quickly tried to merge it with my Scrollable GridView and finally succeeded and here’s it for you an ASP.Net GridView Control with Fixed Headers and scroll functionality with Client Side sorting.
 
GridView Markup
Below is the GridView Markup
<div id = "container" style ="height:200px; overflow:auto; width:617px ">
<asp:GridView ID="GridView1" runat="server"
    AutoGenerateColumns = "false" CssClass = "grid">
   <Columns>
    <asp:BoundField ItemStyle-Width = "200px"
    DataField = "CustomerID" HeaderText = "CustomerId" />
    <asp:BoundField ItemStyle-Width = "200px"
    DataField = "City" HeaderText = "City"/>
    <asp:BoundField ItemStyle-Width = "200px"
    DataField = "Country" HeaderText = "Country"/>
   </Columns>
</asp:GridView>
</div>

You will notice above I have placed the GridView inside a DIV of fixed height and width and setting its overflow property to auto so that the scrollbars are available. Also I have set the width of the Div slightly more than the GridView so that the horizontal scrollbar is hidden and it can accommodate the vertical scrollbar.
 
Binding the GridView
Below are the methods to Bind the GridView control with data
C#
private void BindGrid()
{
    DataTable dt = new DataTable();
    String strConnString = System.Configuration.ConfigurationManager
                .ConnectionStrings["conString"].ConnectionString;
    SqlConnection con = new SqlConnection(strConnString);
    SqlDataAdapter sda = new SqlDataAdapter();
    SqlCommand cmd = new SqlCommand("select * from customers");
    cmd.Connection = con;
    sda.SelectCommand = cmd;
    sda.Fill(dt);
    GridView1.DataSource = dt;
    GridView1.DataBind();
    GridView1.HeaderRow.Attributes["style"] = "display:none";
    GridView1.UseAccessibleHeader = true;
    GridView1.HeaderRow.TableSection = TableRowSection.TableHeader;
}
 
VB.Net
Private Sub BindGrid()
 Dim dt As New DataTable()
 Dim strConnString As [String] = System.Configuration.ConfigurationManager _
                    .ConnectionStrings("conString").ConnectionString
 Dim con As New SqlConnection(strConnString)
 Dim sda As New SqlDataAdapters()
 Dim cmd As New SqlCommand("select * from customers")
 cmd.Connection = con
 sda.SelectCommand = cmd
 sda.Fill(dt)
 GridView1.DataSource = dt
 GridView1.DataBind()
 GridView1.HeaderRow.Attributes("style") = "display:none"
 GridView1.UseAccessibleHeader = True
 GridView1.HeaderRow.TableSection = TableRowSection.TableHeader
End Sub

Above after binding the GridView I am hiding the GridView header row by setting its display to none. If you set ShowHeader to false it will break the working of sorting library. In the next statements I am modifying the GridView settings so that it renders with THEAD and TBODY tags which are necessary for the library in order to sort a table
 
Building the Dummy Header
For preparing the dummy header we will need to extract the header row of the GridView as shown in the screenshot
ScrollableGridViewwith sorting.png
Now complete paste it above the GridView and remove display:none so that the dummy header is visible, I have also provided ID to the dummy header table and your dummyHeader and the scrollable GridView is ready
ScrollableGridViewwith sorting2.png
CSS
Add the following CSS to the head section of the page
<style type = "text/css">
    .sortAsc
    {
        background-image: url(images/asc.gif);
        background-repeat: no-repeat;
        background-position: center right;
        cursor: pointer;
        width:200px;
    }
    .sortDesc
    {
        background-image: url(images/desc.gif);
        background-repeat: no-repeat;
        background-position: center right;
        cursor: pointer;
        width:200px;
    }
    .grid
    {
        font-family:Arial;
        font-size:10pt;
        width:600px
    }
    .grid THEAD
    {
         background-color:Green;
         color:White;
    }
</style>
 
Client Side Sorting
Now for the Client Side Script I have used the tablesorter jQuery Plugin which will be used to sort the GridView control. Hence add the following scripts to your page
<script src="scripts/jquery-1.3.2.min.js" type="text/javascript"></script>
<script src="scripts/jquery.tablesorter.min.js" type="text/javascript"></script>
<script type = "text/javascript">
    $(document).ready(function() {
    $("#<%=GridView1.ClientID%>").tablesorter();
        SetDefaultSortOrder();
    });
 
    function Sort(cell, sortOrder) {
        var sorting = [[cell.cellIndex, sortOrder]];
        $("#<%=GridView1.ClientID%>").trigger("sorton", [sorting]);
        if (sortOrder == 0) {
            sortOrder = 1;
            cell.className = "sortDesc";
        }
        else {
            sortOrder = 0;
            cell.className = "sortAsc";
        }
        cell.setAttribute("onclick", "Sort(this, " + sortOrder + ")");
        cell.onclick = function() { Sort(this, sortOrder); };
        document.getElementById("container").scrollTop = 0;
    }
 
    function SetDefaultSortOrder() {
        var gvHeader = document.getElementById("dummyHeader");
        var headers = gvHeader.getElementsByTagName("TH");
        for (var i = 0; i < headers.length; i++) {
            headers[i].setAttribute("onclick", "Sort(this, 1)");
            headers[i].onclick = function() { Sort(this, 1); };
            headers[i].className = "sortDesc";
        }
    }
</script>

All the client side methods are explained below
The following method notifies the tablesorter library the ID of the control that needs to be sorted and also calls the SetDefaultSortOrder method to set the default sort order.
    $(document).ready(function() {
    $("#<%=GridView1.ClientID%>").tablesorter();
        SetDefaultSortOrder();
    });
 
The following function as the name suggests sets the default sort order for the GridView in the dummy header that we’ve created earlier
function SetDefaultSortOrder() {
        var gvHeader = document.getElementById("dummyHeader");
        var headers = gvHeader.getElementsByTagName("TH");
        for (var i = 0; i < headers.length; i++) {
            headers[i].setAttribute("onclick", "Sort(this, 1)");
            headers[i].onclick = function() { Sort(this, 1); };
            headers[i].className = "sortDesc";
        }
}
 
This function get’s called when user clicks on the header row for sorting it accepts the cell and the sort order in which the grid needs to be sorted.
function Sort(cell, sortOrder) {
        var sorting = [[cell.cellIndex, sortOrder]];
        $("#<%=GridView1.ClientID%>").trigger("sorton", [sorting]);
        if (sortOrder == 0) {
            sortOrder = 1;
            cell.className = "sortDesc";
        }
        else {
            sortOrder = 0;
            cell.className = "sortAsc";
        }
        cell.setAttribute("onclick", "Sort(this, " + sortOrder + ")");
        cell.onclick = function() { Sort(this, sortOrder); };
        document.getElementById("container").scrollTop = 0;
}
 
Checkout the demo GridView below
CustomerId City Country
CustomerId City Country
ALFKI Berlin Germany
ANATR México D.F. Mexico
ANTON México D.F. Mexico
AROUT London UK
BERGS Luleå Sweden
BLAUS Mannheim Germany
BLONP Strasbourg France
BOLID Madrid Spain
BONAP Marseille France
BOTTM Tsawassen Canada
BSBEV London UK
CACTU Buenos Aires Argentina
CENTC México D.F. Mexico
CHOPS Bern Switzerland
COMMI Sao Paulo Brazil
CONSH London UK
DRACD Aachen Germany
DUMON Nantes France
EASTC London UK
ERNSH Graz Austria
FAMIA Sao Paulo Brazil
FISSA Madrid Spain
FOLIG Lille France
FOLKO Bräcke Sweden
FRANK München Germany
FRANR Nantes France
FRANS Torino Italy
FURIB Lisboa Portugal
GALED Barcelona Spain
GODOS Sevilla Spain
GOURL Campinas Brazil
GREAL Eugene USA
GROSR Caracas Venezuela
HANAR Rio de Janeiro Brazil
HILAA San Cristóbal Venezuela
HUNGC Elgin USA
HUNGO Cork Ireland
ISLAT Cowes UK
KOENE Brandenburg Germany
LACOR Versailles France
LAMAI Toulouse France
LAUGB Vancouver Canada
LAZYK Walla Walla USA
LEHMS Frankfurt a.M. Germany
LETSS San Francisco USA
LILAS Barquisimeto Venezuela
LINOD I. de Margarita Venezuela
LONEP Portland USA
MAGAA Bergamo Italy
MAISD Bruxelles Belgium
MEREP Montréal Canada
MORGK Leipzig Germany
NORTS London UK
OCEAN Buenos Aires Argentina
OLDWO Anchorage USA
OTTIK Köln Germany
PARIS Paris France
PERIC México D.F. Mexico
PICCO Salzburg Austria
PRINI Lisboa Portugal
QUEDE Rio de Janeiro Brazil
QUEEN Sao Paulo Brazil
QUICK Cunewalde Germany
RANCH Buenos Aires Argentina
RATTC Albuquerque USA
REGGC Reggio Emilia Italy
RICAR Rio de Janeiro Brazil
RICSU Genève Switzerland
ROMEY Madrid Spain
SANTG Stavern Norway
SAVEA Boise USA
SEVES London UK
SIMOB Kobenhavn Denmark
SPECD Paris France
SPLIR Lander USA
SUPRD Charleroi Belgium
THEBI Portland USA
THECR Butte USA
TOMSP Münster Germany
TORTU México D.F. Mexico
TRADH Sao Paulo Brazil
TRAIH Kirkland USA
VAFFE Århus Denmark
VICTE Lyon France
VINET Reims France
WANDK Stuttgart Germany
WARTH Oulu Finland
WELLI Resende Brazil
WHITC Seattle USA
WILMK Helsinki Finland
WOLZA Warszawa Poland

Browser Compatibility
The above code has been tested in the following browsers only in versions that support HTML5.
 
Internet Explorer  FireFox  Chrome  Safari  Opera 
* All browser logos displayed above are property of their respective owners.
 
 

That’s it with this the article comes to an end. Hope you liked it.
You can download the complete source code in VB.Net and C# using the link below