Is there a way to get the DataGrid control to render the tbody and thead HTML elements?
DataGrid does not have something built-in to accomplish your needs. Take a look on ASP.NET 2.0 CSS Friendly Control Adapters 1.0 they are have built-in support for DataView, but seems you can easily adopt this idea for DataGrid.
Right, looks like the data grid doesn't support this out of the box, so I've had to create a class that inherits from the DataGrid. After the DataGrid has rendered I then parse the HTML and inject the elements in the correct place.
Attached is my class for those that whant to know how. This is a quick and dirty approach, so I'm welcome to better ideas.
Imports System.IO
Imports System.Text
Public Class TestDataGrid
Inherits System.Web.UI.WebControls.DataGrid
Private sTHeadClass As String = String.Empty
Private sTBodyClass As String = String.Empty
Private sTFootClass As String = String.Empty
#Region " Properties "
Public Property THeadClass() As String
Get
Return sTHeadClass
End Get
Set(ByVal value As String)
sTHeadClass = value
End Set
End Property
Public Property TBodyClass() As String
Get
Return sTBodyClass
End Get
Set(ByVal value As String)
sTBodyClass = value
End Set
End Property
Public Property TFootClass() As String
Get
Return sTFootClass
End Get
Set(ByVal value As String)
sTFootClass = value
End Set
End Property
#End Region
Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
Dim oMemoryStream As New MemoryStream()
Dim oStreamWriter As New StreamWriter(oMemoryStream)
Dim oStreamReader As New StreamReader(oMemoryStream)
Dim oHtmlTextWriter As New HtmlTextWriter(oStreamWriter)
MyBase.Render(oHtmlTextWriter)
oHtmlTextWriter.Flush()
oMemoryStream.Flush()
oMemoryStream.Position = 0
Dim sHtml As String = oStreamReader.ReadToEnd()
Dim oHtml As New Text.StringBuilder()
Dim iPastIndex As Integer = 0
Dim iIndex As Integer = sHtml.IndexOf("<tr>")
oHtml.Append(sHtml.Substring(iPastIndex, iIndex - iPastIndex))
iPastIndex = iIndex
If ShowHeader Then
WriteElementStart(oHtml, "thead", sTHeadClass)
'Write Header Row
iIndex = sHtml.IndexOf("</tr>", iPastIndex) + 5
oHtml.Append(sHtml.Substring(iPastIndex, iIndex - iPastIndex))
iPastIndex = iIndex
oHtml.Append("</thead>")
WriteElementStart(oHtml, "tbody", sTBodyClass)
Else
WriteElementStart(oHtml, "tbody", sTBodyClass)
End If
If ShowFooter Then
'Writer Body Rows
iIndex = sHtml.LastIndexOf("<tr>")
oHtml.Append(sHtml.Substring(iPastIndex, iIndex - iPastIndex))
iPastIndex = iIndex
WriteElementEnd(oHtml, "tbody")
WriteElementStart(oHtml, "tfoot", sTFootClass)
'Write Footer Row
iIndex = sHtml.LastIndexOf("</table>")
oHtml.Append(sHtml.Substring(iPastIndex, iIndex - iPastIndex))
iPastIndex = iIndex
WriteElementEnd(oHtml, "tfoot")
Else
iIndex = sHtml.LastIndexOf("</table>")
oHtml.Append(sHtml.Substring(iPastIndex, iIndex - iPastIndex))
iPastIndex = iIndex
WriteElementEnd(oHtml, "tbody")
End If
oHtml.Append(sHtml.Substring(iPastIndex, sHtml.Length - iPastIndex))
writer.Write(oHtml.ToString())
End Sub
Private Sub WriteElementStart(ByVal Builder As StringBuilder, ByVal Tag As String, ByVal CssClass As String)
If String.IsNullOrEmpty(CssClass) Then
Builder.AppendFormat("<{0}>", Tag)
Else
Builder.AppendFormat("<{0} class='{1}'>", Tag, CssClass)
End If
End Sub
Private Sub WriteElementEnd(ByVal Builder As StringBuilder, ByVal Tag As String)
Builder.AppendFormat("</{0}>", Tag)
End Sub
End Class
Yes, solution is described at my blog at http://nmarian.blogspot.com/2007/08/aspnet-datagrid-rendered-with-thead.html
It can be done also via javascript.
function AddTHEAD(tableName)
{
var table = document.getElementById(tableName);
if(table != null)
{
var head = document.createElement("THEAD");
head.style.display = "table-header-group";
head.appendChild(table.rows[0]);
table.insertBefore(head, table.childNodes[0]);
}
}
Then you must call this function on body onload like that:
<body onload="javascript: AddTHEAD('DataGridId')">
Source: http://www.codeproject.com/KB/grid/HeaderOnEachPage.aspx