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

ScrollingGrid: A cross-browser freeze-header two-way scrolling DataGrid

By , 28 Aug 2006
 

Screenshot - Firefox

Test the online demo of ScrollingGrid: Online Demo^ (supports Internet Explorer, Firefox 1.0+, Netscape 7+).

Introduction

This control provides a cross-browser solution to a common problem with large DataGrids: being able to scroll data while keeping the header row frozen above the data. This control allows two-way scrolling - i.e., the header slides left and right as you scroll horizontally.

There is an IE-only solution that has been around for some time, which makes the header row behave like a layer. But one minor issue with it is that dropdown lists float above the header row when scrolling. A major issue with it is that it's IE-only :-).

Advantages over similar controls

  • Cross-browser compatible: Mozilla Firefox 1+, Internet Explorer 5+, Netscape 7+.
  • <select> elements do not float above the header. This is a common complaint with other solutions.
  • Last scroll position is submitted on postback, which you can then use to set the start scroll position.
  • You still use the ASP.NET DataGrid control, so you don't lose Intellisense in Visual Studio's HTML editor (for grid columns etc.).

Disadvantages

  • It only freezes header and bottom-pager rows. It does not freeze columns (similar IE-only controls can).

Other points

  • Simple implementation.
  • Supports multiple scrolling grids on the same page.
  • Doesn't work with Opera browser (yet).
  • If JavaScript is disabled, the entire original DataGrid will scroll within the main DIV (i.e., the header doesn't freeze).

Using the ScrollingGrid

Visual Studio designer

  1. Download and extract the DLL zip file to the root of your web project:
    bin/ScrollingGrid.dll
    ScrollingGrid.js
  2. Add the ScrollingGrid control to your toolbox by browsing to bin/ScrollingGrid.dll.
  3. Create a ScrollingGrid control on your page.
  4. Drag a DataGrid into the ScrollingGrid control.
  5. If your page is not in the root of your web project, you will need to specify the ScriptPath property. E.g., ScriptPath="../".

Visual Studio HTML view

  1. Download and extract the DLL zip file to the root of your web project:
    bin/ScrollingGrid.dll
    ScrollingGrid.js

    Now add a reference to ScrollingGrid.dll in your web project. Alternatively, you can add ScrollingGrid.cs to your project (included in the source ZIP), instead of using ScrollingGrid.dll (which you should delete in this case).

  2. In your .aspx page:
    1. Register the TagPrefix:
      <%@ Register TagPrefix=avg Assembly=ScrollingGrid 
                                 Namespace=AvgControls %>
    2. Within your web form, surround your DataGrid control with the ScrollingGrid control as follows:
      <form runat="server">
      
        <avg:ScrollingGrid runat="server" ID=sg1 
             Width=450 Height=240 CssClass=sgTbl>
      
          <asp:DataGrid runat="server" ID=Grid2 CellPadding=5 CellSpacing=1
            AutoGenerateColumns=True AllowSorting=True 
            AllowPaging=True PageSize=35
            OnPageIndexChanged=Grid2_PageIndexChanged 
            AllowCustomPaging=True>
              <HeaderStyle BackColor=red ForeColor=white Font-Bold=True />
              <ItemStyle BackColor=#fefefe />
              <AlternatingItemStyle BackColor=#eeeeee />
              <PagerStyle BackColor=silver ForeColor=White 
                          Mode=NumericPages />
          </asp:DataGrid>
      
        </avg:ScrollingGrid>
      
      </form>
    3. If your page is not in the root of your web project, you will need to specify the ScriptPath property. E.g., ScriptPath="../".

ScrollingGrid notes

  • The Width, Height, ScriptPath, and CssClass properties are all optional and have default values.
  • The Width value may be pixels or percentage.
  • The Height value must be pixels (not percentage), and corresponds to the height of the DIV that contains the data rows. Since the header and pager are moved outside this DIV, your total height will be slightly larger.
  • The ScrollingGrid expects only the DataGrid as a child control.
  • If your DataGrid contains a bottom pager, it will be automatically frozen underneath the content rows.
  • If your ScrollingGrid is not contained within a web form, you should reference the JavaScript file in your HEAD tag:
    <script language="JavaScript" src="ScrollingGrid.js"></script>
  • Some properties cannot be changed at runtime because the ScrollingGrid creates the control structure in the OnInit method (seemed to be the only way the DataGrid postback functionality could be preserved). E.g., the DataGrid's ShowHeader and the ScrollingGrid's ScrollingEnabled property.
  • Images in your DataGrid may get clipped in Internet Explorer if you don't set their width attribute.
  • If you use the Visual Studio .NET designer, you can add this control to your toolbox. Then, just drag it to the page, and drag your DataGrid into the ScrollingGrid.

DataGrid notes

There are a couple of points to be aware of when it comes to your DataGrid control:

  • If you do not set the CellPadding attribute of your DataGrid, the ScrollingGrid control will assign a value of 2. The default value of -1 causes problems in Firefox.
  • The ScrollingGrid control automatically assigns GridLines=None on your DataGrid control; otherwise, Firefox will ignore your CellSpacing value. This is a common problem with the DataGrid in Firefox.
  • The ScrollingGrid control automatically sets your DataGrid's BorderWidth=0 property; otherwise, Firefox doesn't match up the columns accurately. If you need to display borders on your DataGrid table, I recommend setting the CellSpacing property to the width of the border (and must also have GridLines=None). Then, set your ScrollingGrid's BackColor property (which will show through as the border color).

ScrollingGrid class

Summary

Cross-browser container control for a DataGrid to freeze its header and bottom pager while scrolling both horizontally and vertically.

Syntax

public class ScrollingGrid : System.Web.UI.WebControls.Panel

Members (Excluding inherited)

FirefoxBorderWorkaround

Set to false if GridLines and BorderWidth properties on the DataGrid should not be set for optimal results in Firefox.

  • Type: Boolean
  • Default: True

FooterWidthReduction

Get/set pixel width to reduce the footer by

  • Type: Int32
  • Default: 0

HeaderWidthReduction

Get/set pixel width to reduce the header by, e.g., 17 = scrollbar width (if you don't want the header to extend across the top of the scrollbar)

  • Type: Int32
  • Default: 0

OnInit(EventArgs)

Creates the controls before and after the child DataGrid control.

  • Return Type: void

Overflow

Content DIV overflow style setting. Can be: auto, scroll, hidden.

  • Type: String
  • Default: scroll

RenderBeginTag(HtmlTextWriter)

Output's start of control's container TABLE.

  • Return Type: void

RenderEndTag(HtmlTextWriter)

Output's end of control's container TABLE

  • Return Type: void

ScriptPath

Get/set the location of ScrollingGrid.js

  • Type: String
  • Default:

ScrollingEnabled

Set to false to display the DataGrid as normal (i.e., without any scrolling or frozen header etc.)

  • Type: Boolean
  • Default: True

SetStartScrollPosFromPostack()

Set starting scroll position of content DIV from postback.

  • Return Type: void

StartScrollPos

Get/set the start scroll position of the content DIV.

  • Type: Point
  • Default: new Point(0, 0)

Inherited properties

Only these inherited properties have any effect on the HTML output:

  • BackColor
  • CssClass
  • Height
  • Width

How it works

I had the initial idea after being presented with a question at a job interview, a few years ago. The idea being that the header could actually be an entirely separate table, with the column widths matching exactly with the content table. Both tables would be in their own DIVs. The header DIV would hide the overflow. The content DIV would scroll. When the user scrolls the content DIV across, the header DIV is automatically scrolled to the same horizontal scroll-value. And when the user scrolls the content DIV down, the header remains in view.

However, manually setting column widths is not practical. And making a new grid control would have limited appeal, since most developers are used to the functionality of the DataGrid control. It was about a year ago that I started working on the idea of rendering it around the DataGrid control. But one problem is that the DataGrid doesn't give you a way to get the header HTML only. But accessing the header row in the browser's DOM is simple enough. So as the page is loading in the browser, the script simply reassigns the header TR to a new table.

But moving the header row does not keep the original column widths. So, they then need to be dynamically matched up. Once that is done, it pretty much looks like the original table, with scrollbars for the data rows, and a "frozen" header row that slides left and right as the data is scrolled.

As for the ASP.NET control, the ScrollingGrid class inherits from the Panel control in order to be VS.NET designer-friendly. However, the HTML output is completely custom, so most of the Panel's inherited properties have no effect. The ScrollingGrid expects a DataGrid child-control, and adds its HTML around the DataGrid. The main reason I did not inherit from the DataGrid class is that you would lose VS.NET Intellisense when coding the DataGrid in HTML mode (quite frustrating if you code ASP.NET pages in HTML mode).

The code

Most of this control's functionality is in the JavaScript initialisation of the control in the browser. The DataGrid's header row and bottom pager row are moved to their respective place-holder tables. Then, the header and content column widths are sync'd by increasing the width of the narrowest column.

Column widths are often influenced by the total width of the table. In Internet Explorer, you can change this behaviour by setting tableEl.style.tableLayout = "fixed". However, in Firefox, this doesn't seem to have any effect, so instead, you need to make sure the table has plenty of room to expand. This is accomplished by setting the width of the outer place-holder table extremely wide (i.e., 10000).

Here is an excerpt from the initScrollingGrid() JavaScript function (to move the header TR element to the place-holder table):

var tblHdr = document.getElementById(scrollingGridID + "$tblHdr");
var tblDataGrid = document.getElementById(gridID);
var tblPager = document.getElementById(scrollingGridID + "$tblPager");

// get header table's first row
var tbodyEl = tblHdr.childNodes[firstChildElIndex(tblHdr, "TBODY")];
var trEl = tbodyEl.childNodes[firstChildElIndex(tbodyEl, "TR")];

// get datagrid table's first row
var tbodyEl2 = tblDataGrid.childNodes[firstChildElIndex(tblDataGrid, "TBODY")];
var trEl2 = tbodyEl2.childNodes[firstChildElIndex(tbodyEl2, "TR")];

// delete empty TR on placeholder table
tbodyEl.removeChild(trEl);

// move the header row from datagrid table to our placeholder table
tbodyEl.appendChild(trEl2);

The firstChildElIndex function is a necessary step for Firefox, in response to an annoying behaviour - namely that white-space results in a "#text" childNode in the DOM tree. So in some cases, TBODY is the first childNode of TABLE, and in other cases, the second childNode (depending on whether there is white-space between <table> and <tr>).

Here is an excerpt from the SetWidths JavaScript function:

for (var i=0; i<widths.length; i++)
{
    if (widths[i]+"" == "undefined")
        continue;

    // TD element for the header row
    var tdHdr = trEl.childNodes[i];

    // TD element for the content row
    var tdContent = trEl2.childNodes[i];

    var widthAdjustment = 0;
    if (!document.all)
    {
        // FF: subtract cellpadding
        widthAdjustment = -2 * parseInt(tblGrid.getAttribute("cellpadding"));
    }

    // Update either the header cell or content cell
    // (not both, otherwise FF stuffs up)
    if (tdHdr.offsetWidth != widths[i])
        // update header column width
        tdHdr.style.width = widths[i] + widthAdjustment;
    if (tdContent.offsetWidth != widths[i])
        // update content column width
        tdContent.style.width = widths[i] + widthAdjustment;
}

The widths array is populated in a previous loop, and contains the correct width for each column. So here, the appropriate table cells are adjusted to their new width.

To sync the header with the content, this simple JavaScript function handles scroll events on the content DIV:

// content scroll event handler (matches the header row
// with the horizontal scroll position of content)
function updateScroll(divObj, scrollingGridID)
{
    if (document.getElementById(scrollingGridID + "$divHdr") != null)
        document.getElementById(scrollingGridID + "$divHdr").scrollLeft = 
                                                       divObj.scrollLeft;

    // save scroll position to hidden input
    document.getElementById(scrollingGridID + "$hdnScrollPos").value = 
                            divObj.scrollLeft + "-" + divObj.scrollTop;
}

Even though the header DIV does not display a scrollbar, its scrollLeft property still shifts the position of its content.

Issues

  • In Firefox (versions prior to 1.5), if you drag to select text in the content table and cause the content DIV to scroll, the scroll event handler does not fire and so the header doesn't get sync'd.
  • In Firefox (versions prior to 1.5), the mouse wheel doesn't work with DIVs. This is a browser behaviour.
  • To disable the scrolling behaviour, the ScrollingEnabled property of the ScrollingGrid has to be specified in the control's server tag (not code-behind). Setting this at runtime doesn't work. This is a side-effect of setting all the controls in the OnInit method (which is necessary to avoid issues with the DataGrid's postback events). I'll have to experiment with a few other ideas to work around this limitation.

Points of interest

  • The rendering behaviour of IE vs. FF is very different. Developing the variable width functionality was much easier with Firefox which renders tables as you would expect when specifying percentage widths. However, IE reacted completely differently. Because the DIVs within the outer table contained a lot of content (even though the overflow was clipped), IE was making the outer table really wide to accommodate the content. The solution was to use table-layout:fixed which tells IE to listen to the specified table widths (and clip any wide content). I then use the script to update the DIV widths to the same width as the TD.
  • Large amounts of data don't seem to present any problems. The header-row doesn't sync quite as instantly when there are thousands of rows. And the browser takes up a lot of memory and CPU. But from what I could tell, no more so than using a DataGrid on its own.
  • Developing the DHTML to work with Firefox + IE was a challenge, primarily because the Firefox DOM creates #text nodes even when there is only whitespace between HTML tags.
  • If you want to clip the text in a column (and not have it wrap), you need to create a TemplateColumn and do some fancy stuff with CSS and a DIV. Firefox scores extra points here because you can actually highlight the text and it will slide across within the clipped area, whereas IE just clips it. Here is the TemplateColumn to achieve this:
    <asp:TemplateColumn Visible=True HeaderText=ShipName>
      <ItemTemplate>
        <div style="overflow:hidden; text-overflow:clip; width:70px;">
           <nobr><%# DataBinder.Eval(Container.DataItem, "ShipName") %></nobr>
        </div>
      </ItemTemplate>
    </asp:TemplateColumn>

Conclusion

Developing cross-browser DHTML can be a real challenge, but in my opinion, Firefox is a great browser, and its continued popularity warrants the extra effort. It's definitely been a good lesson in browser rendering behaviours as well as developing custom controls. Feel free to leave feedback below if you find this control useful.

Updates

August 2006 - Major improvements to the control. Reworked this article.

  • Now supports variable width (i.e., percentage).
  • Submits the last scroll position on postback, which can optionally be used to set the start scroll position (using the new StartScrollPos property).
  • Utility function to scale the height when the browser is resized.
  • Added a property to specify the path to ScrollingGrid.js.

License

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

About the Author

Ashley van Gerven
Australia Australia
Member
Ash is a C# developer (MCAD) with a background developing e-commerce and content management solutions. His current role includes working with VOIP systems, integration and maintenance of business and billing apps. His personal projects include the ScrollingGrid web control to enable cross-browser freeze-header 2-way scrolling of DataGrids. His other interests include travel, cinema, Squash, photography, Muay Thai.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
Bugitems didn't match to its headermemberEiramave Panambo22 Jan '13 - 18:06 
Hi,
 
I'm currently using your scroll grid in my project. But when i tried to put it inside content template or iframe, the items didn't matched/aligned to its header.
 
Please help..
 
Thanks,
 
Eee
GeneralProblem to make it workmemberOtavio Camargo5 Apr '11 - 3:59 
Hi,
I added the ScrollingGrid.dll as reference to my project and the ScrollingGrid.js in the work.
But an error ocurrs in the js while trying to get the div called "divContent".
I searched it on the demo page html source, and it was there. But in my page, I can't find it.
This DIV should be created by the component or a must create it manually? here is my implementation:
 
&lt;avg:ScrollingGrid ID="sg1" runat="server" Width="450" Height="130" HeaderWidthReduction="17" BorderColor="Red" ScrollingEnabled="true"&gt;
                                
                                &lt;asp:GridView ID="GvBusca" runat="server" AutoGenerateColumns="false" Width="600px"&gt;
                                    &lt;HeaderStyle CssClass="tableHead1" /&gt;
                                    &lt;RowStyle CssClass="linhaListagem1" /&gt;
                                    &lt;AlternatingRowStyle CssClass="linhaListagem2" /&gt;
                                    &lt;EmptyDataRowStyle CssClass="linhaListagem2" /&gt;
                                    &lt;Columns&gt;
                                        &lt;asp:BoundField DataField="CD_ESPECIE" ItemStyle-HorizontalAlign="Left" HeaderText="Espécie"&gt;
                                            &lt;ItemStyle Wrap="false" /&gt;
                                            &lt;HeaderStyle Wrap="false" /&gt;
                                        &lt;/asp:BoundField&gt;&lt;/asp:DataGrid&gt;
 
		&lt;/avg:ScrollingGrid&gt;<

GeneralRe: Problem to make it work (GridView)memberOtavio Camargo5 Apr '11 - 4:20 
I found out the problem.
The problem is that this component works only with DataGrid.
I was trying with GridView.
Is there a version of this component working with GridView?
Thanks
GeneralRe: Problem to make it work (GridView)memberAshley van Gerven5 Apr '11 - 15:35 
Hi - someone has updated it to work with GridView: ScrollingGrid: A cross-browser freeze-header two-way scrolling DataGrid[^]
 
You could try that.
 

cheers
"For fifty bucks I'd put my face in their soup and blow." - George Costanza
CP article: SmartPager - a Flickr-style pager control with go-to-page popup layer.

QuestionIs it possible to fix 1st column in datagrid herememberrajas44449 Nov '10 - 23:13 
Hi,
This article is somuch helpful..here I want to freeze the one column of datagrid while horizontal scrolling....Can any one suggest the solution...
Thanking you...
GeneralMy vote of 5 [modified]memberrajas44442 Nov '10 - 19:19 
This article is awesome.I tried somany options but I failed in cross browser support.Here I got solution exactly.

modified on Sunday, November 7, 2010 11:42 PM

GeneralFixed Header does not work OnItemDataBound [modified]memberFranklin57757 Oct '10 - 9:01 
Ashley,
 
Thanks for sharing this code, I have a requirement to change the header label or different conditions, so I use the OnItemDataBound event to change the Header labels, the Header labels do get changed but the Fixed Header property doesn't work. I using the DataGrid inside and UpdatePanel.
Do you have any work around or solution for this.
 
This is ScrollingGrid code snippet
 
<avg:ScrollingGrid ID="ScrollDGSource" runat="server" BorderWidth="1" BorderColor="SlateGray" 
    ScriptPath="../../Javascript/" Height="100px" Width="215px">
    <asp:DataGrid ID="gridSource" runat="server" SkinID="None" AutoGenerateColumns="False" AllowSorting="False" Width="205px" OnItemDataBound="OnSourceGridItemDataBound" >
        <HeaderStyle HorizontalAlign="Center"  BackColor="#F6DFE4" Font-Bold="true" ForeColor="Black" />
        <Columns>
            <asp:TemplateColumn>
                <HeaderTemplate>
                    <asp:CheckBox ID="chkItemHeader" runat="server" />
                </HeaderTemplate>
                <ItemTemplate>
                    <asp:CheckBox ID="chkItem" runat="server" />
                </ItemTemplate>
            </asp:TemplateColumn>
            <asp:BoundColumn  HeaderText="J#" DataField = "JNoCtrlLot" ItemStyle-HorizontalAlign="center" ItemStyle-Wrap="False"  ItemStyle-Width="80px"/>
            <asp:BoundColumn  HeaderText="Analyser" DataField = "AnalyserTypeCtrlNo" ItemStyle-HorizontalAlign="center" ItemStyle-Wrap="False"  ItemStyle-Width="60px"/>
        </Columns>
 </asp:DataGrid>
</avg:ScrollingGrid> 
 

This is my OnItemDataBound
protected void OnSourceGridItemDataBound(object sender, DataGridItemEventArgs e)
{
if(e.Item.ItemType == ListItemType.Header) // || (e.Item.ItemType == ListItemType.AlternatingItem))
{
if (rbMultiJNo.Checked == true)
{
e.Item.Cells[1].Text = "J#";
e.Item.Cells[2].Text = "Analyser";
}
else if (rbMultiControlNo.Checked == true)
{
e.Item.Cells[1].Text = "Control Lot";
e.Item.Cells[2].Text = "Control #";
}
}
 
}
}

modified on Thursday, October 7, 2010 4:37 PM

Generalwere is source for dllmemberdfsfdds17 Aug '10 - 6:01 
you idiot
GeneralProblem using AJAX UpdatePanel ...ContinuedmemberMcSmack5 Jan '10 - 6:58 
Just following up on the post back in '08 from Jocke
 
"Hi, 
 
Great control!
I have one problem though:
When I am adding an UpdatePanel on the page the control starts to behave a bit strange.
I have paging and sorting set to true on the grid and when I click on either sorting or paging buttons, the footer is moved back into the grid again. I still want it outside the scrolling area.
Can I not use Ajax with this control? I really would like to...
 
Thanks in advance for your help! 
 
Jocke"
 
Has anyone found a solution to this?
 
Any help is much appreciated. Thank You.
 
Mike
GeneralRe: Problem using AJAX UpdatePanel ...Continuedmemberpowerpo2 Dec '10 - 22:34 
Hi,
I think I have get the key to solove the problem.
It's cause by updatepanel, if you use a inline javascript in updatepanel, they will think the content had been build in client and escape to run javascript in client again ,even you put them into a dom object.
the solution is use ScriptManager's RegisterScriptBlock function, ajax will do javascript again
Here is code , I just modify Ashley van Gerven's code a little at OnInit event:
/// <summary>
/// Adds the necessary HTML before and after it's DataGrid child control
/// </summary>
/// <param name="e"></param>
protected override void OnInit(EventArgs e)
{
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "ScrollingGrid_js", "<script language=JavaScript src=" + ScriptPath + "ScrollingGrid.js></script>");
 
// find the DataGrid control
foreach (Control c in this.Controls)
{
if (c is GridView)
{
grid = (GridView)c;
break;
}
}
 
if (grid != null && ScrollingEnabled)
{
if (FirefoxBorderWorkaround)
{
// for best results in Firefox set these properties on the DataGrid
grid.GridLines = GridLines.None;
grid.BorderWidth = 0;
}
 

StringBuilder html = new StringBuilder();
 
if (grid.ShowHeader)
{
string divHdrStyle = "overflow:hidden;";
if (HeaderWidthReduction > 0)
divHdrStyle += string.Format("margin-right:{0}px;", HeaderWidthReduction);
 
// header div
html.AppendFormat("<div id={0}$divHdr style='{1}'>\r\n", this.ClientID, divHdrStyle);
 
// header table borders
string border = "0";
string style = " style='border-collapse:collapse;'";
if (!grid.BorderWidth.IsEmpty)
border = grid.BorderWidth.Value.ToString();
else if (grid.GridLines == GridLines.Both)
border = "1";
 
if (grid.CellSpacing > 0) // FF doesn't display cellspacing correctly with border-collapse style
style = "";
 
string borderColor = "";
if (!grid.BorderColor.IsEmpty)
{
string colorValue = grid.BorderColor.Name;
if (colorValue.StartsWith("ff"))
colorValue = "#" + colorValue.Substring(2);
borderColor = " borderColor='" + colorValue + "'";
}
 
// container table + header table
if (grid.CellPadding == -1)
grid.CellPadding = 2;
string cellpadding = string.Format("cellpadding='{0}'", grid.CellPadding);
html.AppendFormat("<table cellpadding=0 cellspacing=0 id={3}$headerCntr><tr><td><table id={3}$tblHdr border='{0}' {1} cellspacing='{2}' {4}{5}>", border, cellpadding, grid.CellSpacing, this.ClientID, borderColor, style);
html.Append(" <tr></tr></table></td></tr></table>\r\n");
 
//close header div
html.Append("</div>\r\n");
}
 

// scrolling div + 2nd container table
html.AppendFormat("<div id={3}$divContent style='height:{1};overflow:{2};' onscroll='updateScroll(this, \"{3}\")'><table cellpadding=0 cellspacing=0 id={3}$contentCntr><tr><td>", Width, Height, this.Overflow, this.ClientID);
 

// insert our html as the first control
this.Controls.AddAt(0, new LiteralControl(html.ToString()));
 

// close container table & scrolling div (appended to end)
string appendHtml = "";
if (grid.ShowHeader)
appendHtml += "</td></tr></table>\r\n";
appendHtml += "</div>\r\n";
 

// hidden input for scroll position
appendHtml += string.Format("<input type=hidden name={0}$hdnScrollPos id={0}$hdnScrollPos>\r\n", this.ClientID);
 

this.Controls.Add(new LiteralControl(appendHtml));
 

// check for datagrid pager
bool lastRowIsPager = false;
if (grid.AllowPaging && grid.PagerSettings.Visible && (grid.PagerSettings.Position == PagerPosition.Bottom || grid.PagerSettings.Position == PagerPosition.TopAndBottom))
{

lastRowIsPager = true;

// pager table underneath scrolling grid
string tblPagerStyle = "width:100%;";
if (FooterWidthReduction > 0)
  tblPagerStyle += string.Format("margin-right:{0}px;", FooterWidthReduction);
 
this.Controls.Add(new LiteralControl(string.Format("<table id={0}$tblPager cellpadding={1} cellspacing={2} style='{3}'> <tr></tr></table>\r\n", this.ClientID, grid.CellPadding, grid.CellSpacing, tblPagerStyle)));

}
 
// javacript to initialise grid
if (grid.ShowHeader)
{
string script = string.Format("<script language=javascript name="+Guid.NewGuid()+">\r\n<!--\r\n setTimeout(\"initScrollingGrid('{0}', '{1}', {2})\", 50) \r\n//--></script>", this.ClientID, grid.ClientID, lastRowIsPager.ToString().ToLower());

ScriptManager sm = ScriptManager.GetCurrent(Page);
if (sm != null && sm.IsInAsyncPostBack)
{
script = string.Format("setTimeout(\"initScrollingGrid('{0}', '{1}', {2})\", 50);", this.ClientID, grid.ClientID, lastRowIsPager.ToString().ToLower());

ScriptManager.RegisterClientScriptBlock(this, typeof(Page), "scrolling grid script"+this.ClientID, script, true);

}
else
{
this.Controls.Add(new LiteralControl(script));
}
}

}
 
this.Load += new EventHandler(ScrollingGrid_Load);
base.OnInit(e);
}

 
Hope can help you!
And Ashley van Gerven, it's great work,thanks a lot for your project, it's very useful,haha
GeneralHeader don't Fix in 3.5memberfavre nicolas21 Dec '09 - 21:10 
Hello,
 
I've used your control on a first project developped with Framework 2.0 and it works fine.
 
Now I want to use it in a project with Framework 3.5. The scrolling works but the header isn't fix and i don't understand why. The grid is in a page which is herited a Masterpage.
 
Does anyone experience the same problem ?
 
Thanks for your help.
 
Nicolas
QuestionCannot view project in VS2003 or VS2008.memberMcSmack17 Dec '09 - 8:07 
I'm new to Web Development, so I need a little help creating my tool at work.
 
I'm having some troubles trying to load the source project in either VS2003 or VS2008. VS2008 will try and convert it, claims it was successful, then when loading the environment unloads the ScrollingGrid files.
 
VS2003 reports that it cannot open because there is "no Web Server detected at URL:'http://Localhost:/_dev/ScrollingGrid'.
 
Anyone have any ideas?
 
Thanks in advance for any help.
AnswerCan't get the header or pager to freeze in ASP.NET 3.5memberMcSmack18 Dec '09 - 4:34 
Just a follow up.
 
I'm not sure why I couldn't load it, but I found a work around by just creating a new project and then importing all the files to create the new GridView DLL version.
 
But now I cannot get the header or pager to freeze in VS2008 ASP.NET 3.5? Has anyone else experienced this?
QuestionScrollingGrid with GridViewmemberJon Rupert19 Oct '09 - 11:30 
Trying to get this to work with a gridview. Copied code posted that was indicated to work with gridview, but I have NO ScrollBars and the Header does not freeze. Could you indicate specifically which lines would need to change in ScrollingGrid.js. Thank you in advance for your assistance.
GeneralError in ScrollingGrid.js, line 66, Invalid Argument. Error goes away on page refresh.memberAnil Karahana10 Oct '09 - 2:27 
I have few textboxes and dropdown lists on my page and a search button. After filling textboxes and selecting values in dropdown, I click Search button and on click, Datagrid with scrollingGrid control is displayed. See sample code below.
 
                                    <tr>
                                        <td align="left">
                                            <cc1:ScrollingGrid ID="divFreightRate1" Visible="false" Width="100%" Height="150px"
                                                ScrollBars="Auto" runat="server">
                                                <asp:DataGrid ID="dgOceanFreightRate" runat="server" AllowPaging="True" AutoGenerateColumns="False"
                                                    PagerStyle-HorizontalAlign="Left" OnPageIndexChanged="dgOceanFreightRate_PageIndexChanged"
                                                    PagerStyle-Mode="NextPrev" PagerStyle-NextPageText="Next" PagerStyle-Position="Bottom"
                                                    Font-Size="8pt" HeaderStyle-ForeColor="white" PagerStyle-PrevPageText="Prev"
                                                    PageSize="20" CellSpacing="1" GridLines="None">
                                                    <Columns>
                                                        <asp:TemplateColumn>
                                                            <HeaderTemplate>
                                                                <input disabled="disabled" type="checkbox" /></HeaderTemplate>
                                                            <ItemTemplate>
                                                                <asp:CheckBox ID="chkItem" runat="server" />
                                                            </ItemTemplate>
                                                        </asp:TemplateColumn>
                                                        <asp:TemplateColumn HeaderText="S.No." HeaderStyle-Font-Bold="true" HeaderStyle-HorizontalAlign="Center">
                                                            <ItemStyle HorizontalAlign="left" />
                                                            <ItemTemplate>
                                                                <%# (dgOceanFreightRate.PageSize * dgOceanFreightRate.CurrentPageIndex) + Container.ItemIndex + 1%>
                                                            </ItemTemplate>
                                                        </asp:TemplateColumn>
...20 more columns here...
                                                    </Columns>
                                                    <HeaderStyle CssClass="head_bg_crm" />
                                                    <AlternatingItemStyle CssClass="grid_bg" />
                                                    <PagerStyle HorizontalAlign="Left" NextPageText="Next" Position="Bottom" PrevPageText="Prev" />
                                                </asp:DataGrid>
                                            </cc1:ScrollingGrid>
 
It shows javascript error message and data is not displayed properly in Grid. but when I refresh the page, it works fine, no error.
 
I have enabled script debugging to see the exact javascript error mentioned in the subject line.

Strange behavior: Scrolling Grid works fine at my local machine, issue occurs at test and production server. My local machine is windows XP and server machine is windows 2003 server, standard edition.
 
Please reply ASAP.
GeneralHi Ashleymemberavinashpatil3484new6 Oct '09 - 4:33 
Hello
Thanks man, for a such good article and code.
It helped me in my requirement.
Ones again thanks .......
bye tc
 
Avinash Patil
avinashpatil3484@gmail.com
QuestionHorizontal scrollmemberPreeyab22 Jul '09 - 0:58 
Can someone please tell me how to avoid the horizontal scroll bar in this control? I want to show only the vertical scroll for the data grid in my web page. Please help.
GeneralSample in VB codememberRevalk3 Jul '09 - 5:34 
This is a very nice article. Is there a sample of this in VB code ?
 
Thanx,
 
Herman
GeneralGridView extra row problemmemberPak51413 Jan '09 - 9:52 
Anyone encounter this when apply this code to gridview. An extra row is appended to the bottom of the grid.
GeneralRe: GridView extra row problemmemberPak51414 Jan '09 - 13:17 
Solved the problem by removing the footer because it wasn't working.
QuestionScrollingGrid breaks if using Pagingmemberawhig19 Dec '08 - 6:18 
I converted ScrollingGrid to use a GridView. This works ok. I have a GridView where I am using the built in Paging. The Paging is set for Top. Because the pager is at the top (it's the first row in the table), the ScrollingGrid thinks this is the header and freezes it and my real header is not frozen.
 
Has anyone created a work around for this?
 
I do not want to go and have to rework my gridviews to use a separate paging component and change more code.
 
Thanks,
Rich
QuestionCan you converted it working in GridView [modified]memberMember 77170318 Dec '08 - 18:15 
the grid working very well, Please help us to convert it that works on asp.net gridview
 
modified on Friday, December 19, 2008 12:50 AM

AnswerRe: Can you converted it working in GridViewmemberawhig19 Dec '08 - 6:12 
I have it working with a GridView. It was very easy to convert, but here is my source code. Just update ScrollingGrid.cs
 
Rich
 

 

/*
* Copyright © 2005, Ashley van Gerven (ashley.vg@gmail.com)
* All rights reserved.
*
* Use in source and binary forms, with or without modification, is permitted
* provided that the above copyright notice and disclaimer below is not removed.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* http://www.codeproject.com/KB/webforms/ScrollingGrid.aspx
*/
 

using System;
using System.Drawing;
using System.IO;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
 

namespace AvgControls
{
     /// <summary>
     /// Cross-browser container control for a DataGrid to freeze it's header and bottom pager while scrolling both horizontally and vertically.
     /// </summary>
     [ToolboxData("<{0}:ScrollingGrid runat=server></{0}:ScrollingGrid>")]
     [ToolboxBitmap(typeof(ScrollingGrid), "ScrollingGridIcon.bmp")]
     public class ScrollingGrid : Panel
     {
            private GridView grid = null;
 

          /// <summary>
          /// Content DIV overflow style setting. Can be: auto, scroll, hidden
          /// </summary>
          public string Overflow = "scroll";
 
          /// <summary>
          /// Get/set pixel width to reduce the header by - e.g. 17 = scrollbar width (if you don't want the header to extend accross the top of the scrollbar)
          /// </summary>
          public int HeaderWidthReduction = 0;
 
          /// <summary>
          /// Get/set pixel width to reduce the footer by
          /// </summary>
          public int FooterWidthReduction = 0;
 
          /// <summary>
          /// Set to false to display the DataGrid as normal (i.e. without any scrolling or frozen header etc.)
          /// </summary>
          public bool ScrollingEnabled = true;
 
          /// <summary>
          /// Get/set the start scroll position of the content DIV
          /// </summary>
          public Point StartScrollPos = new Point(0, 0);
 
          /// <summary>
          /// Get/set the location of ScrollingGrid.js
          /// </summary>
          public string ScriptPath = "";
 
          /// <summary>
          /// Set to false if GridLines &amp; BorderWidth properties on DataGrid should not be set for optimal results in Firefox
          /// </summary>
          public bool FirefoxBorderWorkaround = true;
 

 
          /// <summary>
          /// Constructor
          /// </summary>
          public ScrollingGrid()
          {
               // Initialise width & height
               this.Width = 450;
               this.Height = 200;
          }
 

          /// <summary>
          /// Adds the necessary HTML before and after it's DataGrid child control
          /// </summary>
          /// <param name="e"></param>
          protected override void OnInit(EventArgs e)
          {
                  Page.ClientScript.RegisterClientScriptBlock(this.GetType(),"ScrollingGrid_js", "<script language=JavaScript src=" + ScriptPath + "ScrollingGrid.js></script>");
 
               // find the DataGrid control
               foreach (Control c in this.Controls)
               {
                    if (c is GridView)
                    {
                              grid = (GridView)c;
                         break;
                    }
               }
 
               if (grid != null && ScrollingEnabled)
               {
                    if (FirefoxBorderWorkaround)
                    {
                         // for best results in Firefox set these properties on the DataGrid
                         grid.GridLines = GridLines.None;
                         grid.BorderWidth = 0;
                    }
 

                    StringBuilder html = new StringBuilder();
 
                    if (grid.ShowHeader)
                    {
                         string divHdrStyle = "overflow:hidden;";
                         if (HeaderWidthReduction > 0)
                              divHdrStyle += string.Format("margin-right:{0}px;", HeaderWidthReduction);
 
                         // header div
                         html.AppendFormat("<div id={0}$divHdr style='{1}'>\r\n", this.ClientID, divHdrStyle);
 
                         // header table borders
                         string border = "0";
                         string style = " style='border-collapse:collapse;'";
                         if (!grid.BorderWidth.IsEmpty)
                              border = grid.BorderWidth.Value.ToString();
                         else if (grid.GridLines == GridLines.Both)
                              border = "1";
 
                         if (grid.CellSpacing > 0) // FF doesn't display cellspacing correctly with border-collapse style
                              style = "";
 
                         string borderColor = "";
                         if (!grid.BorderColor.IsEmpty)
                         {
                              string colorValue = grid.BorderColor.Name;
                              if (colorValue.StartsWith("ff"))
                                   colorValue = "#" + colorValue.Substring(2);
                              borderColor = " borderColor='" + colorValue + "'";
                         }
 
                         // container table + header table
                         if (grid.CellPadding == -1)
                              grid.CellPadding = 2;
                         string cellpadding = string.Format("cellpadding='{0}'", grid.CellPadding);
                         html.AppendFormat("<table cellpadding=0 cellspacing=0 id={3}$headerCntr><tr><td><table id={3}$tblHdr border='{0}' {1} cellspacing='{2}' {4}{5}>", border, cellpadding, grid.CellSpacing, this.ClientID, borderColor, style );
                         html.Append(" <tr></tr></table></td></tr></table>\r\n");
 
                         //close header div
                         html.Append("</div>\r\n");
                    }
 

                    // scrolling div + 2nd container table
                    html.AppendFormat("<div id={3}$divContent style='height:{1};overflow:{2};' onscroll='updateScroll(this, \"{3}\")'><table cellpadding=0 cellspacing=0 id={3}$contentCntr><tr><td>", Width, Height, this.Overflow, this.ClientID);
 

                    // insert our html as the first control
                    this.Controls.AddAt(0, new LiteralControl(html.ToString()));
 

                    // close container table & scrolling div (appended to end)
                    string appendHtml = "";
                    if (grid.ShowHeader)
                         appendHtml += "</td></tr></table>\r\n";
                    appendHtml += "</div>\r\n";
 

                    // hidden input for scroll position
                    appendHtml += string.Format("<input type=hidden name={0}$hdnScrollPos id={0}$hdnScrollPos>\r\n", this.ClientID);
 

                    this.Controls.Add(new LiteralControl(appendHtml));
 

                    // check for datagrid pager
                    bool lastRowIsPager = false;
                        if (grid.AllowPaging && grid.PagerSettings.Visible && (grid.PagerSettings.Position == PagerPosition.Bottom || grid.PagerSettings.Position == PagerPosition.TopAndBottom))
                    {
                         lastRowIsPager = true;
 
                         // pager table underneath scrolling grid
                         string tblPagerStyle = "width:100%;";
                         if (FooterWidthReduction > 0)
                              tblPagerStyle += string.Format("margin-right:{0}px;", FooterWidthReduction);
 
                         this.Controls.Add(new LiteralControl( string.Format("<table id={0}$tblPager cellpadding={1} cellspacing={2} style='{3}'> <tr></tr></table>\r\n", this.ClientID, grid.CellPadding, grid.CellSpacing, tblPagerStyle) ));
                    }
 
                    // javacript to initialise grid
                    if (grid.ShowHeader)
                         this.Controls.Add( new LiteralControl(string.Format("<script language=javascript>\r\n<!--\r\n setTimeout(\"initScrollingGrid('{0}', '{1}', {2})\", 50) \r\n//--></script>", this.ClientID, grid.ClientID, lastRowIsPager.ToString().ToLower())) );
               }
 
               this.Load += new EventHandler(ScrollingGrid_Load);
               base.OnInit(e);
          }
 

          /// <summary>
          /// Outputs start of control's container TABLE
          /// </summary>
          /// <param name="writer"></param>
          public override void RenderBeginTag(HtmlTextWriter writer)
          {
               // bg color style
               string style = "";
               if (!this.BackColor.IsEmpty)
               {
                    string colorValue = this.BackColor.Name;
                    if (colorValue.StartsWith("ff"))
                         colorValue = "#" + colorValue.Substring(2);
                    style = string.Format("background-color:{0};", colorValue);
               }
 
               if (ScrollingEnabled)
                    style += string.Format("width:{0};", this.Width);
 
               string html = string.Format("<table id={0} name=ScrollingGrid style='{1} table-layout:fixed' cellpadding=0 cellspacing=0 border=0", this.ClientID, style);
               if (this.CssClass != null && this.CssClass.Length > 0)
                    html += string.Format(" class='{0}'", this.CssClass);
               html += "><tr><td>\r\n";
               writer.Write(html);
          }
 

          /// <summary>
          /// Outputs end of control's container TABLE
          /// </summary>
          /// <param name="writer"></param>
          public override void RenderEndTag(HtmlTextWriter writer)
          {
               writer.Write("</td></tr></table>\r\n");
          }
 

          /// <summary>
          /// Set starting scroll position of content DIV from postback
          /// </summary>
          public void SetStartScrollPosFromPostack()
          {
               string key = this.ClientID + "$hdnScrollPos";
               if (HttpContext.Current.Request.Form[key] != null && HttpContext.Current.Request.Form[key].Length > 0)
               {
                    string[] parts = HttpContext.Current.Request.Form[key].Split('-');
                    this.Controls.Add( new LiteralControl(string.Format("<script language=javascript>\r\n<!--\r\n setTimeout(\"setContentScrollPos('{0}', {1}, {2})\", 100) \r\n//--></script>", this.ClientID, parts[0], parts[1])) );
               }
          }
 

          /// <summary>
          /// Control's Load event handler
          /// </summary>
          private void ScrollingGrid_Load(object sender, EventArgs e)
          {
               // add JS to set the starting scroll position
               if (this.StartScrollPos.X > 0 || this.StartScrollPos.Y > 0)
                    this.Controls.Add( new LiteralControl(string.Format("<script language=javascript>\r\n<!--\r\n setTimeout(\"setContentScrollPos('{0}', {1}, {2})\", 100) \r\n//--></script>", this.ClientID, this.StartScrollPos.X, this.StartScrollPos.Y)) );
          }
     }
}
GeneralI need it to work with Gridview, not DatagridmemberKauey18 Dec '08 - 1:58 
Hi all,
I' downloaded the project, and tested it.
It works very well, but the fact is that the project is based on a Datagrid sollution.
I need it to work with Gridview.
 
Can someone help me?
Thnx,
Kauey
AnswerRe: I need it to work with Gridview, not Datagridmemberawhig19 Dec '08 - 6:13 
I have it working with a GridView. It was very easy to convert, but here is my source code. Just update ScrollingGrid.cs
 
Rich
 

 

/*
* Copyright © 2005, Ashley van Gerven (ashley.vg@gmail.com)
* All rights reserved.
*
* Use in source and binary forms, with or without modification, is permitted
* provided that the above copyright notice and disclaimer below is not removed.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* http://www.codeproject.com/KB/webforms/ScrollingGrid.aspx
*/
 

using System;
using System.Drawing;
using System.IO;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.ComponentModel;
 

namespace AvgControls
{
     /// <summary>
     /// Cross-browser container control for a DataGrid to freeze it's header and bottom pager while scrolling both horizontally and vertically.
     /// </summary>
     [ToolboxData("<{0}:ScrollingGrid runat=server></{0}:ScrollingGrid>")]
     [ToolboxBitmap(typeof(ScrollingGrid), "ScrollingGridIcon.bmp")]
     public class ScrollingGrid : Panel
     {
            private GridView grid = null;
 

          /// <summary>
          /// Content DIV overflow style setting. Can be: auto, scroll, hidden
          /// </summary>
          public string Overflow = "scroll";
 
          /// <summary>
          /// Get/set pixel width to reduce the header by - e.g. 17 = scrollbar width (if you don't want the header to extend accross the top of the scrollbar)
          /// </summary>
          public int HeaderWidthReduction = 0;
 
          /// <summary>
          /// Get/set pixel width to reduce the footer by
          /// </summary>
          public int FooterWidthReduction = 0;
 
          /// <summary>
          /// Set to false to display the DataGrid as normal (i.e. without any scrolling or frozen header etc.)
          /// </summary>
          public bool ScrollingEnabled = true;
 
          /// <summary>
          /// Get/set the start scroll position of the content DIV
          /// </summary>
          public Point StartScrollPos = new Point(0, 0);
 
          /// <summary>
          /// Get/set the location of ScrollingGrid.js
          /// </summary>
          public string ScriptPath = "";
 
          /// <summary>
          /// Set to false if GridLines &amp; BorderWidth properties on DataGrid should not be set for optimal results in Firefox
          /// </summary>
          public bool FirefoxBorderWorkaround = true;
 

 
          /// <summary>
          /// Constructor
          /// </summary>
          public ScrollingGrid()
          {
               // Initialise width & height
               this.Width = 450;
               this.Height = 200;
          }
 

          /// <summary>
          /// Adds the necessary HTML before and after it's DataGrid child control
          /// </summary>
          /// <param name="e"></param>
          protected override void OnInit(EventArgs e)
          {
                  Page.ClientScript.RegisterClientScriptBlock(this.GetType(),"ScrollingGrid_js", "<script language=JavaScript src=" + ScriptPath + "ScrollingGrid.js></script>");
 
               // find the DataGrid control
               foreach (Control c in this.Controls)
               {
                    if (c is GridView)
                    {
                              grid = (GridView)c;
                         break;
                    }
               }
 
               if (grid != null && ScrollingEnabled)
               {
                    if (FirefoxBorderWorkaround)
                    {
                         // for best results in Firefox set these properties on the DataGrid
                         grid.GridLines = GridLines.None;
                         grid.BorderWidth = 0;
                    }
 

                    StringBuilder html = new StringBuilder();
 
                    if (grid.ShowHeader)
                    {
                         string divHdrStyle = "overflow:hidden;";
                         if (HeaderWidthReduction > 0)
                              divHdrStyle += string.Format("margin-right:{0}px;", HeaderWidthReduction);
 
                         // header div
                         html.AppendFormat("<div id={0}$divHdr style='{1}'>\r\n", this.ClientID, divHdrStyle);
 
                         // header table borders
                         string border = "0";
                         string style = " style='border-collapse:collapse;'";
                         if (!grid.BorderWidth.IsEmpty)
                              border = grid.BorderWidth.Value.ToString();
                         else if (grid.GridLines == GridLines.Both)
                              border = "1";
 
                         if (grid.CellSpacing > 0) // FF doesn't display cellspacing correctly with border-collapse style
                              style = "";
 
                         string borderColor = "";
                         if (!grid.BorderColor.IsEmpty)
                         {
                              string colorValue = grid.BorderColor.Name;
                              if (colorValue.StartsWith("ff"))
                                   colorValue = "#" + colorValue.Substring(2);
                              borderColor = " borderColor='" + colorValue + "'";
                         }
 
                         // container table + header table
                         if (grid.CellPadding == -1)
                              grid.CellPadding = 2;
                         string cellpadding = string.Format("cellpadding='{0}'", grid.CellPadding);
                         html.AppendFormat("<table cellpadding=0 cellspacing=0 id={3}$headerCntr><tr><td><table id={3}$tblHdr border='{0}' {1} cellspacing='{2}' {4}{5}>", border, cellpadding, grid.CellSpacing, this.ClientID, borderColor, style );
                         html.Append(" <tr></tr></table></td></tr></table>\r\n");
 
                         //close header div
                         html.Append("</div>\r\n");
                    }
 

                    // scrolling div + 2nd container table
                    html.AppendFormat("<div id={3}$divContent style='height:{1};overflow:{2};' onscroll='updateScroll(this, \"{3}\")'><table cellpadding=0 cellspacing=0 id={3}$contentCntr><tr><td>", Width, Height, this.Overflow, this.ClientID);
 

                    // insert our html as the first control
                    this.Controls.AddAt(0, new LiteralControl(html.ToString()));
 

                    // close container table & scrolling div (appended to end)
                    string appendHtml = "";
                    if (grid.ShowHeader)
                         appendHtml += "</td></tr></table>\r\n";
                    appendHtml += "</div>\r\n";
 

                    // hidden input for scroll position
                    appendHtml += string.Format("<input type=hidden name={0}$hdnScrollPos id={0}$hdnScrollPos>\r\n", this.ClientID);
 

                    this.Controls.Add(new LiteralControl(appendHtml));
 

                    // check for datagrid pager
                    bool lastRowIsPager = false;
                        if (grid.AllowPaging && grid.PagerSettings.Visible && (grid.PagerSettings.Position == PagerPosition.Bottom || grid.PagerSettings.Position == PagerPosition.TopAndBottom))
                    {
                         lastRowIsPager = true;
 
                         // pager table underneath scrolling grid
                         string tblPagerStyle = "width:100%;";
                         if (FooterWidthReduction > 0)
                              tblPagerStyle += string.Format("margin-right:{0}px;", FooterWidthReduction);
 
                         this.Controls.Add(new LiteralControl( string.Format("<table id={0}$tblPager cellpadding={1} cellspacing={2} style='{3}'> <tr></tr></table>\r\n", this.ClientID, grid.CellPadding, grid.CellSpacing, tblPagerStyle) ));
                    }
 
                    // javacript to initialise grid
                    if (grid.ShowHeader)
                         this.Controls.Add( new LiteralControl(string.Format("<script language=javascript>\r\n<!--\r\n setTimeout(\"initScrollingGrid('{0}', '{1}', {2})\", 50) \r\n//--></script>", this.ClientID, grid.ClientID, lastRowIsPager.ToString().ToLower())) );
               }
 
               this.Load += new EventHandler(ScrollingGrid_Load);
               base.OnInit(e);
          }
 

          /// <summary>
          /// Outputs start of control's container TABLE
          /// </summary>
          /// <param name="writer"></param>
          public override void RenderBeginTag(HtmlTextWriter writer)
          {
               // bg color style
               string style = "";
               if (!this.BackColor.IsEmpty)
               {
                    string colorValue = this.BackColor.Name;
                    if (colorValue.StartsWith("ff"))
                         colorValue = "#" + colorValue.Substring(2);
                    style = string.Format("background-color:{0};", colorValue);
               }
 
               if (ScrollingEnabled)
                    style += string.Format("width:{0};", this.Width);
 
               string html = string.Format("<table id={0} name=ScrollingGrid style='{1} table-layout:fixed' cellpadding=0 cellspacing=0 border=0", this.ClientID, style);
               if (this.CssClass != null && this.CssClass.Length > 0)
                    html += string.Format(" class='{0}'", this.CssClass);
               html += "><tr><td>\r\n";
               writer.Write(html);
          }
 

          /// <summary>
          /// Outputs end of control's container TABLE
          /// </summary>
          /// <param name="writer"></param>
          public override void RenderEndTag(HtmlTextWriter writer)
          {
               writer.Write("</td></tr></table>\r\n");
          }
 

          /// <summary>
          /// Set starting scroll position of content DIV from postback
          /// </summary>
          public void SetStartScrollPosFromPostack()
          {
               string key = this.ClientID + "$hdnScrollPos";
               if (HttpContext.Current.Request.Form[key] != null && HttpContext.Current.Request.Form[key].Length > 0)
               {
                    string[] parts = HttpContext.Current.Request.Form[key].Split('-');
                    this.Controls.Add( new LiteralControl(string.Format("<script language=javascript>\r\n<!--\r\n setTimeout(\"setContentScrollPos('{0}', {1}, {2})\", 100) \r\n//--></script>", this.ClientID, parts[0], parts[1])) );
               }
          }
 

          /// <summary>
          /// Control's Load event handler
          /// </summary>
          private void ScrollingGrid_Load(object sender, EventArgs e)
          {
               // add JS to set the starting scroll position
               if (this.StartScrollPos.X > 0 || this.StartScrollPos.Y > 0)
                    this.Controls.Add( new LiteralControl(string.Format("<script language=javascript>\r\n<!--\r\n setTimeout(\"setContentScrollPos('{0}', {1}, {2})\", 100) \r\n//--></script>", this.ClientID, this.StartScrollPos.X, this.StartScrollPos.Y)) );
          }
     }
}
GeneralRe: I need it to work with Gridview, not DatagridmemberMiguelAJH18 Aug '10 - 18:42 
hI.. THANKS...
I have a problem..
I can build with this code a dll for use it.
But .. the gridview.. alwas all collumns have the same width..
 
I have a image:
 
http://www.dumppix.com/viewer.php?file=igm_prorlema_gridview.jpg
 
http://www.dumppix.com/viewer.php?file=igm_prorlema_gridview.jpg[^]
 
can you or somebody ... help?.
thanks
El diablo no sabe ni por diablo ni por viejo sino porque lee los manuales

GeneralSaved my lifememberPak51429 Nov '08 - 15:20 
I've been searching for a week now for a solution to this common problem, but for the gridview. I'm pretty sure this will work for it with a bit of tweaking. Thanks!!
QuestionGridview and Firefox 3membermorsanu23 Nov '08 - 22:40 
I adapted your code for a Gridview control, it works ok in IE, but in Firefox the widths of the header columns are not set correctly. Is there a known solution or should I continue digging for one myself?
AnswerRe: Gridview and Firefox 3memberAshley van Gerven24 Nov '08 - 2:47 
My demo using the DataGrid works with Firefox 3 but I'm not aware of a solution using the GridView I'm afraid.
 
"For fifty bucks I'd put my face in their soup and blow." - George Costanza
CP article: SmartPager - a Flickr-style pager control with go-to-page popup layer.

GeneralRe: Gridview and Firefox 3membermorsanu24 Nov '08 - 4:33 
I changed this :
 
if (tdHdr.offsetWidth != widths[i])
tdHdr.style.width = widths[i] + widthAdjustment;
if (tdContent.offsetWidth != widths[i])
tdContent.style.width = widths[i] + widthAdjustment;
 
into this:
 
if (tdHdr.offsetWidth != widths[i])
tdHdr.style.width = (widths[i] + widthAdjustment) + "px";
if (tdContent.offsetWidth != widths[i])
tdContent.style.width = (widths[i] + widthAdjustment) + "px";
 
and it worked. Now I shall see what problems I'll hit next.
QuestionRe: Gridview and Firefox 3 [modified]membermorsanu24 Nov '08 - 22:01 
As I said before, I managed to set the correct widths. But it seems that this is the case just when the width of the control is bigger than the gridview's. When it is smaller, everything loads ok, but then all the widths shrink.
 
modified on Tuesday, November 25, 2008 4:32 AM

QuestionProblem using AJAX UpdatePanelmemberbentherunner18 Nov '08 - 10:12 
Hi,
 
Great control!
I have one problem though:
When I am adding an UpdatePanel on the page the control starts to behave a bit strange.
I have paging and sorting set to true on the grid and when I click on either sorting or paging buttons, the footer is moved back into the grid again. I still want it outside the scrolling area.
Can I not use Ajax with this control? I really would like to...
 
Thanks in advance for your help!
 
Jocke
AnswerRe: Problem using AJAX UpdatePanelmemberAdriano Evangelista29 Jan '09 - 0:42 
Hi,
 
I have same problem with Ajax Updade Panel, someone has idea of how to this problem.
thanks,
GeneralRe: Problem using AJAX UpdatePanelmemberMurty200925 Mar '09 - 7:22 
I'm having the same issue, does anyone know how to get around this. Ajax has been defined in the base class so is inherited in my search page where this grid is and therefore doesn't allow the headers to be frozen. Has anyone come across a solution where they can get past this?
GeneralRe: Problem using AJAX UpdatePanelmemberAdriano Evangelista3 Apr '09 - 4:29 
Hi,
 
I resolve this problem, in original code the header and pager are excluded. I change the attribute display=none in header and pager to hide and using the function clone to copy the two thus, maintaining the original.
Because when use update panel this component take the first line and last line, in original code the first time are excluded header and pager.
GeneralRe: Problem using AJAX UpdatePanelmemberMember 31994086 May '09 - 1:45 
Adriano,
 
Could you please provide me the code u used for solving the problem. I too have the same problem please consider it as urgently.Iam waiting for your response.
 
Thanks
Khaliq
GeneralRe: Problem using AJAX UpdatePanelmemberMcSmack17 Dec '09 - 11:01 
Did you ever get a response for the solution? I'm experiencing the same problem with using GridView instead of DataGrid.
QuestionRe: Problem using AJAX UpdatePanelmemberAnil Karahana26 Aug '09 - 1:42 
Hi,
 
I have a issue with Ajax update panel. I don't see the scrollbars when I visit the page, but when I make some changes on the page and cancel changes, then the page reloads and scrollbars are visible properly.
Strange behaviour Frown | :(
 
Please help me solve this problem.
Generalhelp me !!!! codes "gridview " freeze-header two-way scrolling with errormemberNitish.112730 Oct '08 - 22:42 
////code on form
 
&lt;script language="javascript"&gt;
 

function CreateNonScrollHeader(curHdrRowid,newHdrid)
                  {
                     var curHdrRowid=document.getElementById(curHrdRowid);
                     var newHdrid=document.getElementById(newHdrid);
                     copyAttributes(curHdrRowid, newHdrid);
                     //newHdrid.innerHtml=curHdrRowId.innerHtml;
                     for(var i=0;i&lt;curHdrRowid.cells.length;i++)
                        {
                              var curHdrCell=curHdrRowid.cells.item(i);
                              var newHdrCell=document.createElement("th");
                              copyAttributes(curHdrCell,newHdrCell);
                              newHdrcell.innerHtml=curHdrCell.innerHtml;
                              newHdrRowid.appendChild(newHdrCell);
                        }
                        curHdrRowid.style.display="none";
 
                  }
 
     
      &lt;/script&gt;
 

code on code behind page
 
protected void gvTable_PreRender(object sender, EventArgs e)
      {
        
            try
            {
                  string jvScript = "&lt;script language=\"javascript\"&gt;\n";
                  this.gvTable.HeaderRow= "tr_Header";
                  jvScript += "CreateNonScrollHeader(" + gvTable.HeaderRow.ClientID + "," +tr_Header.ClientID + ");\n";
                  jvScript += "&lt;/script&gt;";
                  Page.ClientScript.RegisterStartupScript(this.GetType(), "CreateNonScrollHeader", jvScript);
            }
            catch(Exception ee)
            {
                 
            }
      }
 
error are........
 

1)     Property or indexer 'System.Web.UI.WebControls.GridView.HeaderRow' cannot be assigned to -- it is read only
2)     Cannot implicitly convert type 'string' to 'System.Web.UI.WebControls.GridViewRow'
3)     The name 'tr_Header' does not exist in the current context
GeneralShow Sorting Images in Header Rowmemberapsingh0811 Sep '08 - 8:03 
That's a very nice article and it helped me. But I am trying to display sort images when a column is sorted. It is not working for me. Do you think about it or have any solution for this? Thanks again.
 
Abhay Prakash Singh

GeneralFreeze Gridview HeadermemberSathyaSiva19 Jun '08 - 0:48 
I referred following link for freeze gridview header. it's working fine. but In Fire fox The columns not align properly. please anyone help me
http://www.codeproject.com/KB/webforms/ScrollingGrid.aspx[^]
 
Sathya

QuestionHow to make the two-way header sort in AJAX?memberRukawaErj2 Jun '08 - 10:05 
Hi, I was wondering if its possible to sort the headers without postback. How can you do that? Im using the Anthem controls for AJAX implementation. thanks
GeneralCan't make it work properly on Firefox 2memberasfaya21 May '08 - 6:47 
Hi. First of all, excellent job.
Very nice control.
Width very little work I converted it so I can use it with GridView.
But I'm not being able to get it work correctly on FF2.
Can't make it scroll horizontally.
Do you know how can I make to make it work on FF?
I'm posting the generated code in case you want to check it.
Thanks!
 
<table id=ctl00_Main_sg1 name=ScrollingGrid style='width:600px; table-layout:fixed' cellpadding=0 cellspacing=0 border=0><tr><td>
<div id=ctl00_Main_sg1$divHdr style='overflow:hidden;margin-right:20px;'>
<table cellpadding=0 cellspacing=0 id=ctl00_Main_sg1$headerCntr><tr><td><table id=ctl00_Main_sg1$tblHdr border='0' cellpadding='0' cellspacing='0' style='border-collapse:collapse;'> <tr></tr></table></td></tr></table>
</div>
<div id=ctl00_Main_sg1$divContent style='height:275px;overflow:scroll;' onscroll='updateScroll(this, "ctl00_Main_sg1")'><table cellpadding=0 cellspacing=0 id=ctl00_Main_sg1$contentCntr><tr><td>
<div>
<table class="Grid" cellspacing="0" cellpadding="0" border="0" id="ctl00_Main_grdLotes" style="border-width:0px;border-collapse:collapse;">
<tr class="GridHeader GridTitle">
<th scope="col" style="width:40px;">Legajo</th><th scope="col" style="width:230px;">Nombre</th><th scope="col" style="width:30px;">Npi</th><th align="center" scope="col" style="width:90px;"><span>2</span></th><th align="center" scope="col" style="width:90px;"><span>7</span></th><th align="center" scope="col" style="width:90px;"><span>8</span></th><th align="center" scope="col" style="width:90px;"><span>16</span></th><th align="center" scope="col" style="width:90px;"><span>27</span></th><th align="center" scope="col" style="width:90px;"><span>40</span></th><th align="center" scope="col" style="width:90px;"><span>41</span></th><th align="center" scope="col" style="width:90px;"><span>1527</span></th><th align="center" scope="col" style="width:90px;"><span>1529</span></th><th align="center" scope="col" style="width:90px;"><span>1650</span></th><th align="center" scope="col" style="width:90px;"><span>1653</span></th><th align="center" scope="col" style="width:90px;"><span>1670</span></th>
</tr><tr class="GridField">
<td align="center" style="width:40px;">1</td><td style="width:230px;">GONZALEZ GARCIA DE ALBA, DAVID</td><td align="center" style="width:30px;">5394</td><td align="center" style="width:90px;"><input name="ctl00$Main$grdLotes$ctl02$ctl01" type="text" value="0" size="4" class="TextBox" style="width:20px;" /><span>H</span></td><td align="center" style="width:90px;"><input name="ctl00$Main$grdLotes$ctl02$ctl04" type="text" value="0" size="4" class="TextBox" style="width:20px;" /><span></span></td><td align="center" style="width:90px;"><input name="ctl00$Main$grdLotes$ctl02$ctl07" type="text" value="0" size="4" class="TextBox" style="width:20px;" /><span>I</span></td><td align="center" style="width:90px;"><input name="ctl00$Main$grdLotes$ctl02$ctl10" type="text" value="0" size="4" class="TextBox" style="width:20px;" /><span>I</span></td><td align="center" style="width:90px;"><input name="ctl00$Main$grdLotes$ctl02$ctl13" type="text" value="0" size="4" class="TextBox" style="width:20px;" /><span></span></td><td align="center" style="width:90px;"><input name="ctl00$Main$grdLotes$ctl02$ctl16" type="text" value="0" size="4" class="TextBox" style="width:20px;" /><span>D</span></td><td align="center" style="width:90px;"><input name="ctl00$Main$grdLotes$ctl02$ctl19" type="text" value="0" size="4" class="TextBox" style="width:20px;" /><span>D</span></td><td align="center" style="width:90px;"><input name="ctl00$Main$grdLotes$ctl02$ctl22" type="text" value="0" size="4" class="TextBox" style="width:20px;" /><span>I</span></td><td align="center" style="width:90px;"><input name="ctl00$Main$grdLotes$ctl02$ctl25" type="text" value="0" size="4" class="TextBox" style="width:20px;" /><span></span></td><td align="center" style="width:90px;"><input name="ctl00$Main$grdLotes$ctl02$ctl28" type="text" value="0" size="4" class="TextBox" style="width:20px;" /><span>I</span></td><td align="center" style="width:90px;"><input name="ctl00$Main$grdLotes$ctl02$ctl31" type="text" value="0" size="4" class="TextBox" style="width:20px;" /><span>I</span></td><td align="center" style="width:90px;"><input name="ctl00$Main$grdLotes$ctl02$ctl34" type="text" value="0" size="4" class="TextBox" style="width:20px;" /><span>I</span></td>
</tr>
</table>
</div>
</td></tr></table>
</div>
<input type=hidden name=ctl00_Main_sg1$hdnScrollPos id=ctl00_Main_sg1$hdnScrollPos>
<script language=javascript>
<!--
setTimeout("initScrollingGrid('ctl00_Main_sg1', 'ctl00_Main_grdLotes', false, 0, 0);", 50)
//--></script></td></tr></table>
QuestionEdit cells in datgridmemberMember 46290704 Mar '08 - 5:43 
I have an edit linkbutton as a column value and when I wish to edit a
cell (esp. if it's the first row in the grid) the header duplicates
itself. Is there a fix for this?
 
RF
General.NET 2.0 conversion easy!memberdennisbetten25 Feb '08 - 5:12 
Hi! The source is great! In May 2007 you mentioned wanting to rewrite it to VS2005 .NET 2.0. I see you haven't done this yet, and there is no reason to! Automatic conversion by VS2005 works like a charme...
 
thnx Dennis
 
modified on Tuesday, February 26, 2008 3:21 PM

GeneralRe: .NET 2.0 conversion easy!memberAndrew Bacon6 Mar '08 - 9:31 
How do you do this automatic conversion? I have implemented a ScrollingGrid in a project but I'm not getting scroll bars and the appearance of my previously existing datagrid is messed up (font size, width, scrollbars, etc)
 
Help?
GeneralRe: .NET 2.0 conversion easy!memberbmzero9 Apr '08 - 6:23 
Using a datagrid with this control in ASP.NET 2.0 works fine, but it does not work with the gridview control. I believe that's what needs updating.
GeneralThanks Mate..memberdinukeponweera22 Feb '08 - 5:42 
Thanks a lot for this Mate. This was really useful.
Generalthis control can't use for ajaxmemberChau Duong18 Dec '07 - 21:19 
Hello anybody
This control can't use for ajax(Microsoft). Help me
GeneralRe: this control can't use for ajaxmemberPak51424 Dec '08 - 7:27 
This is an example of a programmer acting like a user! No detail whatsoever, just "Help me its broken"

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 28 Aug 2006
Article Copyright 2005 by Ashley van Gerven
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid