Click here to Skip to main content
Click here to Skip to main content

Extending ASP.Net Controls: a Scrollable GridView

, 16 Apr 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
Extending the standard ASP.NET GridView control to add a vertical scrollbar in the grid

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 3 options can be configured at runtime, the 4th 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 a in 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 render it in a seperate 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.

    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 inserit it into the header DIV. Make sure the correct styling is applied.
    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 the newly created table (note that this will remove the row from the origional table!).
    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 previous container)
4. Render the header DIV (this will automatically also render its children elements).
     divhead.RenderControl(writer); // will render the DIV including the table containing only the header.
5. Create the body DIV.
     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.
        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).
         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.
        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.
        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)
        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 DIV's 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: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:

 <%@ 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

Version 1.0 published on April 5th 2013

Version 1.1 published on April 17th 2013

License

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

Share

About the Author

Herre Kuijpers
Architect Capgemini
Netherlands Netherlands
Currently Herre Kuijpers is employed at Capgemini Netherlands for over 10 years, where he developed skills with all kinds of technologies, methodologies and programming languages such as c#, ASP.Net, Silverlight, VC++, Javascript, SQL, UML, RUP, WCF. 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

 
QuestionOnClick in templatefield of a linkbutton not firing PinmemberMichael Clinton9-May-14 20:09 
GeneralMy vote of 5 PinmemberMihai MOGA10-May-13 19:29 
GeneralRe: My vote of 5 PinmemberHerre Kuijpers13-May-13 3:05 
GeneralMy vote of 3 Pinmemberrashmi sudha19-Apr-13 3:40 
GeneralMy vote of 5 PinmemberAbinash Bishoyi17-Apr-13 4:44 
QuestionDouble header rows after Postback Pinmembernbr6-Apr-13 18:03 
AnswerRe: Double header rows after Postback PinmemberHerre Kuijpers6-Apr-13 23:47 
GeneralRe: Double header rows after Postback Pinmembernbr8-Apr-13 16:30 
AnswerRe: Double header rows after Postback PinmemberHerre Kuijpers8-Apr-13 21:41 
GeneralRe: Double header rows after Postback Pinmembernbr9-Apr-13 3:14 
AnswerRe: Double header rows after Postback PinmemberHerre Kuijpers16-Apr-13 23:15 
GeneralMy vote of 5 Pinmemberrht3415-Apr-13 6:07 

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

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

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.141216.1 | Last Updated 17 Apr 2013
Article Copyright 2013 by Herre Kuijpers
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid