views:

1176

answers:

4

Is there a way to get the DataGrid control to render the tbody and thead HTML elements?

A: 

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.

Mike Chaliy
That does gridview but not datagrid.
BC
This is just an idea. Equivalent to "Use Control Adapters" but with samples. Because this pack is open sources. Not more.
Mike Chaliy
A: 

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
Ady
Sorry, but I do not like this solution. For example it depends on HtmlWriter used. With UpperCaseHtmlWriter your solution will not work. Also code with MemoryStream... Also HtmlTextWriter...
Mike Chaliy
Could you explain further? The Render method of the control expets an HtmlTextWriter as an input, it's in the definition! What is your objection to MemoryStream, etc.
Ady
+1  A: 

Yes, solution is described at my blog at http://nmarian.blogspot.com/2007/08/aspnet-datagrid-rendered-with-thead.html

Marian Kostal
+1  A: 

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

mavera