Wednesday, December 5, 2007

Freezing asp.net datagrid header

I have seen more queries regarding freezing datagrid header so that when we scroll the datagrid header should be always visible.
After few investigation on net, I have found two good solutions for it:

1. CSS Solution:
Just create following stlye tag

<style type="text/css">
.DataGridFixedHeader {background-color: white; position:relative; top:expression(this.offsetParent.scrollTop);}
</style>


and apply this css to the headerstyle tag of the datagrid as follows:


<headerstyle backcolor="Tan" bold="True" cssclass="DataGridFixedHeader"/>


Thats it you are done, you grid header will be always visible even if you scroll the grid.
This solutions works well if you datagrid is absolutly positioned.

2. HTC solution:
This solution is posted on microsofts blog at http://msdn2.microsoft.com/en-us/library/bb250510.aspx#Webteam11042002_topic2
This samples works with datagrid as well as HTML table.
As a sample create following htc file, this file will be linked in the aspx file containing datagrid.

File: ScrollTable.htc


<PUBLIC:ATTACH event="ondocumentready" HANDLER="onDocumentReady" />
<SCRIPT LANGUAGE="JScript">
function onDocumentReady()
{
// Create elements
var tblHeader = this.cloneNode(false);
var tblBody = this.cloneNode(false);
var divCntr = document.createElement("DIV");

// Get column widths
var rgWidths = new Array();
for (var i = 0; i < this.rows[0].cells.length; i++)
{
rgWidths[i] = this.rows[0].cells[i].offsetWidth;
}

// Add header row
var tbdyHeader = document.createElement("TBODY");
tblHeader.appendChild(tbdyHeader);
tbdyHeader.appendChild(this.rows[0].cloneNode(true));

// Add body rows
var tbdyBody = document.createElement("TBODY");
tblBody.appendChild(tbdyBody);

for (var i = 1; i < this.rows.length; i++)
{
var oRow = this.rows[i].cloneNode(true);
tbdyBody.appendChild(oRow);
}

// Set up body container
divCntr.style.overflow = "auto";
if (this.bodyHeight) divCntr.style.height = this.bodyHeight;
divCntr.appendChild(tblBody);

// Change existing table
for (var i = this.rows.length; i > 0; i--)
{
this.rows[i-1].removeNode(true);
}
var tr1 = this.insertRow();
var td1 = tr1.insertCell();
var tr2 = this.insertRow();
var td2 = tr2.insertCell();

td1.appendChild(tblHeader);
td2.appendChild(divCntr);

// Set column widths of all but the last column
for (var i = 0; i < rgWidths.length - 1; i++)
{
tblHeader.rows[0].cells[i].width = rgWidths[i];
tblBody.rows[0].cells[i].width = rgWidths[i];
}

tblHeader.style.fontSize = "100%";
tblHeader.width = "100%";
tblHeader.style.tableLayout = "fixed";
tblHeader.className = this.headerCSS ? this.headerCSS : "";
tblHeader.border = 0;

tblBody.style.fontSize = "100%";
tblBody.width = "100%";
tblBody.style.tableLayout = "fixed";
tblBody.className = this.bodyCSS ? this.bodyCSS : "";
tblBody.border = 0;

this.cellSpacing = 0;
this.cellPadding = 0;
}
</SCRIPT>
Now we have to included this file using the following syntax:
behavior:url(scrolltable.htc);
Following is the sample html file contents:

<HTML>
<HEAD>
<STYLE>
.tblMain
{
behavior:url(scrolltable.htc);
background-color: highlight;
border: 1px solid darkblue;
font-family: Verdana;
font-size: .8em;
}
.tblHeader
{
color: highlighttext;
}
.tblBody
{
background-color: #EEEEEE;
color: darkblue;
}
</STYLE>
</HEAD>
<BODY>
<TABLE bodyHeight="100" bodyCSS="tblBody" headerCSS="tblHeader"
CLASS="tblMain" WIDTH="75%" CELLSPACING=5 CELLPADDING=0>
<TR>
<TD NOWRAP>Header A</TD>
<TD NOWRAP>Header B</TD>
<TD NOWRAP>Header C</TD>
</TR>
<TR>
<TD>Aaaaaaaaaaaaaaaaaaa</TD><TD>B</TD><TD>Ccccccccccccccccccc</TD>
</TR>
<TR>
<TD>A</TD><TD>Bbbbbbb</TD><TD>C</TD>
</TR>
<TR>
<TD>A</TD><TD>B</TD><TD>C</TD>
</TR>
<TR>
<TD>A</TD><TD>B</TD><TD>C</TD>
</TR>
<TR>
<TD>A</TD><TD>B</TD><TD>C</TD>
</TR>
<TR>
<TD>A</TD><TD>B</TD><TD>C</TD>
</TR>
<TR>
<TD>A</TD><TD>B</TD><TD>C</TD>
</TR>
<TR>
<TD>A</TD><TD>B</TD><TD>C</TD>
</TR>
<TR>
<TD>A</TD><TD>B</TD><TD>C</TD>
</TR>
</TABLE>
</BODY>
</HTML>
for using this with datagrid just add the attributes added to the table tag in above example to the datagrid, e.g. your datagrid declaration will be similar to



<asp:GridView bodyHeight="100" class="tblMain" ID="GridView1" runat="server" AutoGenerateColumns="False" DataKeyNames="DeviceSer"

DataSourceID="SqlDataSource1" BackColor="LightGoldenrodYellow" BorderColor="Tan" BorderWidth="1px" CellPadding="2" ForeColor="Black" GridLines="None" Width="500px" AllowPaging="true" AllowSorting="True">

Hope this helps all you guys.