Click here to Skip to main content
15,867,568 members
Articles / Web Development / ASP.NET

Extending ASP.NET Controls: A Scrollable GridView

Rate me:
Please Sign up or sign in to vote.
5.00/5 (20 votes)
7 Sep 2020CPOL5 min read 80.7K   3K   41   20
Extending the standard ASP.NET GridView control to add a vertical scrollbar in the grid
In this article, you will see an example for extending the standard ASP.NET GridView control with the option to display scrollbars (a.k.a. scrollable table with fixed header), instead of using the standard 'paging', allowing to display all list items at once.

Scrollbar in the GridView

Introduction

Although ASP.NET comes with a large set of customizable webcontrols, you may wish in some cases to extend the functionality and behavior of a webcontrol. Fortunately, ASP.NET controls have a number of extension points:

  1. Customizable properties
  2. Style and CSS-classes
  3. Templating
  4. Overriding

Although the first three options can be configured at runtime, the fourth option will require some coding. Overriding is required when you wish to change the controls' behavior or layout. In such cases, it is typical to create a subclass for the webcontrol in which the overridden methods are implemented.

This article presents an example for extending the standard ASP.NET GridView control with the option to display scrollbars (a.k.a. scrollable table with fixed header), instead of using the standard 'paging', allowing to display all list items at once. This solution is tested with Internet Explorer, Firefox and Chrome.

Background

Web standards prescribe 'paging' functionality when browsing through large lists. The idea is that large lists will take a 'long' time to download, so when using paging, users only need to download a single page with a small number of rows.

The standard ASP.NET GridView supports paging by default. Strangely enough, the GridView does not optimize loading time by much, since the list that is bound to the gridview is stored in the ViewState by default, and therefore still generates a 'large' page resulting in a longer download time.
So one might as well just choose to ignore paging and show the complete list as a whole. This has the advantage that the page does not need to be reloaded each time the user chooses a different page in the grid.

Obviously, the list can become too large to fit on a single webpage, and hence using scrollbars would be a sufficient solution. Something that is quite common in desktop applications. I found however that adding a scrollbar to the GridView is not entirely trivial: the goal is to only have the list items scrollable, while leaving the gridview header fixed.

I've looked for solutions for this issue, however some of the proposed solutions are only compatible for some browsers (e.g., CSS based), others were quite complicated or worked only in certain situations. As far as I've seen, no standard solution is available for the GridView control. The solution presented here is compatible with various common browsers and can be incorporated into any ASP.NET solution with ease. Also, the final rendered HTML is as compact as possible.

Solution

The approach to the solution is not new, e.g., see an example here. Basically, the header row is displayed in a table in a header DIV, while the body rows are displayed in a separate scrollable body DIV element. This approach poses the following issues to solve:

Extracting the Header Row from the GridView and Rendering It in a Separate DIV and TABLE

This requires a bit of tinkering to get it working. It requires an override of the default RenderChildren method of the GridView control. The RenderChildren method is responsible for generating the output which is written to the response object. Instead of generating the default GridView html element, I rearranged and inserted some html elements of my own.

Basically, I'm using the following steps:

  1. Create a new header DIV html element. Assign it a special css-class so it can be accessed from JQuery.
    C#
        System.Web.UI.HtmlControls.HtmlGenericControl divhead = 
                         new System.Web.UI.HtmlControls.HtmlGenericControl("DIV");
        divhead.Attributes["class"] = "GridViewHeaderContainer"; // Assign a css-style 
                                                                 // accessible by jquery
        divhead.Style.Add("overflow", "hidden");                 // Make sure the inner table 
                                                                 // will not overflow
        if (this.Width != Unit.Empty)
            divhead.Style.Add("width", this.Width.ToString());   // Assign new width, 
                                                                 // overrule stylesheet. 
                                                                 // Use width defined 
                                                                 // in the control
  2. Create a new Table object and insert it into the header DIV. Make sure the correct styling is applied.
    C#
    Table tablehead = new Table();
    tablehead.ApplyStyle(this.HeaderStyle);
    tablehead.Style.Add("width", "100%");
    tablehead.ID = ctrl.UniqueID + "$Header";
    divhead.Controls.Add(tablehead);
    
  3. Select the header row in the GridView and insert it into the newly created table (note that this will remove the row from the original table!).
    C#
        WebControl ctrl = (WebControl)this.Controls[0]; // Reference the table
        Control ctrlrow = ctrl.Controls[0];             // Reference the first row: 
                                                        // table->row[0]
        tablehead.Controls.Add(ctrlrow);                // This will automatically 
                                                        // bind the row to the new 
                                                        // parent control (and remove 
                                                        // itself from the previous container)
  4. Render the header DIV (this will automatically also render its children elements).
    C#
         divhead.RenderControl(writer);                 // will render the DIV 
                                                        // including the table 
                                                        // containing only the header.
  5. Create the body DIV.
    C#
    System.Web.UI.HtmlControls.HtmlGenericControl divbody =
                 new System.Web.UI.HtmlControls.HtmlGenericControl("DIV");
    
  6. Set the style attributes of the DIV and make sure it is scrollable.
    C#
            divbody.Attributes["class"] = "GridViewBodyContainer";   // style is hardcoded 
                                                                     // for jquery
            if (this.Width != Unit.Empty)
                divbody.Style.Add("width", this.Width.ToString());   // Assign new width.
    
            if (this.Height != Unit.Empty)                           // Note: if no height
                                                                     // is set, 
                                                                     // scrollbars will not be 
                                                                     // visible since all rows 
                                                                     // will be displayed then
                divbody.Style.Add("height", this.Height.ToString()); // Assign new height.
    
            divbody.Style.Add("margin", "0px");
            divbody.Style.Add("overflow", "hidden");
            divbody.Style.Add("overflow-y", "auto");
  7. Insert the header row back into the original table at position 0 (at the top).
    C#
    ctrl.Controls.AddAt(0, ctrlrow); // This will automatically bind the row
                                     // to the parent table (and remove itself
                                     // from previous container)
    
  8. Insert the GridView table inside the body DIV and render the body DIV.
    C#
    divbody.Controls.AddAt(0, ctrl);  // Bind the table to the body DIV
                                      // (and remove itself from previous container)
    divbody.RenderControl(writer);    // will render the DIV and the included table
    
  9. Insert the table back into the GridView. This is an essential step, as it will restore the GridView into its original state.
    C#
    this.Controls.AddAt(0, ctrl);     // Restore to previous container,
                                      // this way the control will not break
    
  10. Render any other controls contained in the gridview (e.g., the footer):
    C#
    for (int i = 1; i < this.Controls.Count; i++)
    {
        ctrl = (WebControl)this.Controls[i];
        ctrl.RenderControl(writer);
    }
    

Aligning the Columns of the Header Row With the Columns in the Body Table

To make sure the columns of both tables align, some JavaScript/JQuery is used. The script contains a function called UpdateGrid() which is called after the gridview has completely rendered. At this time, the column widths are known and re-aligned at runtime. It will lookup the DIVs based on their css-class and loop through all rows and columns to determine the width. Then it will explicitly set the width for each table cell.

Once finished, it will make the first row in the body (which is the original header row) invisible. Because this is done after rendering, sometimes this may result in the display of 2 headers for a split second. That's the only drawback from this approach.

Using the Grid in an UpdatePanel

In order to support updates of the Grid from within an UpdatePanel, one extra bit of JavaScript is required to make sure the Grid refreshes and realigns properly after each (partial) postback to the server. Every time the UpdatePanel updates its content, it must call the UpdateGrid() JavaScript function. To do this, the following handler must be declared in the webpage right after the ScriptManager declaration:

ASP.NET
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<script type="text/javascript">
    Sys.Application.add_load(function () { UpdateGrid(); });
</script>

This nice little trick will keep the grid in sync with the UpdatePanel.

Using the Code

The provided solution comes in 2 files:

  • ScrollableGridView.cs
  • ScrollableGridView.js

You can add the files to your own ASP.NET solution or use the ScrollableGridView directly from the ControlExtensions component. You will need to add a reference from your web project to the component.

Add the following lines to your webpage:

ASP.NET
<%@ Register TagPrefix="ce" Namespace="Grids" Assembly="ControlExtensions" %>

<!-- add the following js scripts -->;
<script type="text/javascript" src="Scripts/jquery-1.4.1.min.js"></script>
<script type="text/javascript" src="Scripts/ScrollableGridView.js"></script>

...

<!-- insert the scrollable gridview control on the page at the desired position 
make sure to set the Height property of the control to make sure scrollbars are displayed-->
<ce:ScrollableGridView id="ScrollableGridView1" runat="server" height="360px" width="100%">
    <HeaderStyle BackColor="Orange" />
</ce:ScrollableGridView>

...

This is sufficient to support scrolling in the GridView. In the sample application included here, some random rows are generated to fill the list. This is done in the page's code-behind simply for testing purposes.

Additionally, an example webpage is added to show how to use the grid in combination with the UpdatePanel control.

Points of Interest

I was quite happy to find out that the GridView can be rendered quite differently by overriding the RenderChildren method. This allows for easy reuse and extension of existing ASP.NET controls.

History

  • 5th April, 2013: Version 1.0 published
  • 17th April, 2013: Version 1.1 published

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Rubicon
Netherlands Netherlands
Currently Herre Kuijpers is employed at Rubicon. During his career he developed skills with all kinds of technologies, methodologies and programming languages such as c#, ASP.Net, .Net Core, VC++, Javascript, SQL, Agile, Scrum, DevOps, ALM. Currently he fulfills the role of software architect in various projects.

Herre Kuijpers is a very experienced software architect with deep knowledge of software design and development on the Microsoft .Net platform. He has a broad knowledge of Microsoft products and knows how these, in combination with custom software, can be optimally implemented in the often complex environment of the customer.

Comments and Discussions

 
QuestionDouble header columns in a simple Web Form Pin
Info service19-Oct-20 22:21
Info service19-Oct-20 22:21 
QuestionGlad to see I'm not the only one still using WebForms Pin
Member 202563011-Sep-20 1:32
Member 202563011-Sep-20 1:32 
GeneralMy vote of 5 Pin
michauxb8-Sep-20 20:43
michauxb8-Sep-20 20:43 
Questionproject can't be loaded Pin
Member 137479368-Sep-20 8:21
Member 137479368-Sep-20 8:21 
Questionhelpful Pin
User 41802547-Jun-18 2:03
User 41802547-Jun-18 2:03 
QuestionState of objects not saving.. Pin
Member 1121637827-Oct-16 3:59
Member 1121637827-Oct-16 3:59 
QuestionScrollable GridView NOT firing events Pin
Member 858600628-Jun-16 4:29
Member 858600628-Jun-16 4:29 
GeneralMy vote of 5 Pin
Santhakumar M17-Nov-15 2:46
professionalSanthakumar M17-Nov-15 2:46 
QuestionOnClick in templatefield of a linkbutton not firing Pin
Michael Clinton9-May-14 19:09
Michael Clinton9-May-14 19:09 
GeneralMy vote of 5 Pin
Ștefan-Mihai MOGA10-May-13 18:29
professionalȘtefan-Mihai MOGA10-May-13 18:29 
GeneralRe: My vote of 5 Pin
Herre Kuijpers13-May-13 2:05
Herre Kuijpers13-May-13 2:05 
GeneralMy vote of 3 Pin
rashmi sudha19-Apr-13 2:40
rashmi sudha19-Apr-13 2:40 
GeneralMy vote of 5 Pin
Abinash Bishoyi17-Apr-13 3:44
Abinash Bishoyi17-Apr-13 3:44 
QuestionDouble header rows after Postback Pin
nbr6-Apr-13 17:03
nbr6-Apr-13 17:03 
AnswerRe: Double header rows after Postback Pin
Herre Kuijpers6-Apr-13 22:47
Herre Kuijpers6-Apr-13 22:47 
GeneralRe: Double header rows after Postback Pin
nbr8-Apr-13 15:30
nbr8-Apr-13 15:30 
AnswerRe: Double header rows after Postback Pin
Herre Kuijpers8-Apr-13 20:41
Herre Kuijpers8-Apr-13 20:41 
GeneralRe: Double header rows after Postback Pin
nbr9-Apr-13 2:14
nbr9-Apr-13 2:14 
AnswerRe: Double header rows after Postback Pin
Herre Kuijpers16-Apr-13 22:15
Herre Kuijpers16-Apr-13 22:15 
GeneralMy vote of 5 Pin
rht3415-Apr-13 5:07
rht3415-Apr-13 5:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.