Arizona1911
Arizona1911

Reputation: 2201

How Do I Add Colgroup Tag to ASP:Datagrid Control?

How do I add a colgroup tag to the datagrid control so that I can style each column using css?

Upvotes: 3

Views: 3983

Answers (4)

subjectivist
subjectivist

Reputation: 245

To do a COLGROUP tag I used the Render method. This works well because it's fast and does minimal string manipulation. I started with what's below tweaking widths as needed. The browser will expand columns if too narrow. What this does is produce the minimum width for each.

      Protected Overrides Sub Render(ByVal writer As System.Web.UI.HtmlTextWriter)
        If Not Response.IsClientConnected Then Exit Sub
        writer.InnerWriter.Close()
        writer.InnerWriter = New IO.StringWriter
        MyBase.Render(writer)
        Dim buf$ = writer.InnerWriter.ToString
        Dim p As Integer = buf.IndexOf("<thead>")
        If p < 0 Then
          Response.Write("CANNOT FIND THEAD TAG")
          Exit Sub
        End If
        Response.Write(buf.Substring(0, p))
        Response.Write("
    <colgroup>
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    <col style='width:100px;' />
    </colgroup>
    ")
        Response.Write(buf.Substring(p))
      End Sub

Upvotes: 0

Mihail
Mihail

Reputation: 31

I've searched for some days for a solution on how to add ColGroup template to a GridView. Using the answer given by Josh uphere, and a couple of days of reading about derived objects, especially GridView, I thought that an updated and working solution would help people around.

Imports System.ComponentModel
Imports System.Web.UI
Imports Microsoft.VisualBasic
Imports System.IO

Namespace CustomControls
<ToolboxData("<{0}:GridViewColGroup runat=server></{0}:GridViewColGroup>")> _
<System.Security.Permissions.PermissionSetAttribute(System.Security.Permissions.SecurityAction.Demand, Name:="FullTrust"), _
ParseChildren(True)> _
Public Class GridViewColGroup
    Inherits GridView
    Implements INamingContainer

    Private _ColGroup As ColGroup = Nothing
    Private _ColGroupTemplate As ITemplate = Nothing

    <Browsable(False), _
    Description("The ColGroup template."), _
    TemplateContainer(GetType(ColGroup)), _
    PersistenceMode(PersistenceMode.InnerProperty)> _
    Public Overridable Property ColGroupTemplate() As ITemplate
        Get
            Return _ColGroupTemplate
        End Get
        Set(ByVal value As ITemplate)
            _ColGroupTemplate = value
        End Set
    End Property

    <Browsable(False), _
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)> _
    Public Property ColGroup() As ColGroup
        Get
            Me.EnsureChildControls()
            Return _ColGroup
        End Get
        Set(ByVal value As ColGroup)
            _ColGroup = value
        End Set
    End Property

    Protected Overrides Sub CreateChildControls()
        MyBase.CreateChildControls()

        _ColGroup = New ColGroup()

        If Not ColGroupTemplate Is Nothing Then
            ColGroupTemplate.InstantiateIn(_ColGroup)
        End If

        Me.Controls.Add(_ColGroup)
    End Sub

    Protected Overrides Sub Render(ByVal writer As HtmlTextWriter)
        EnsureChildControls()
        ' Get the base class's output
        Dim sw As New StringWriter()
        Dim htw As New HtmlTextWriter(sw)
        MyBase.Render(htw)
        Dim output As String = sw.ToString()
        htw.Close()
        sw.Close()

        ' Insert a <COLGROUP> element into the output
        Dim pos As Integer = output.IndexOf("<tr")

        If pos <> -1 AndAlso _ColGroup IsNot Nothing Then
            sw = New StringWriter()
            htw = New HtmlTextWriter(sw)
            _ColGroup.RenderPrivate(htw)
            output = output.Insert(pos, sw.ToString())
            htw.Close()
            sw.Close()
        End If

        ' Output the modified markup
        writer.Write(output)
    End Sub
End Class


<ToolboxItem(False)> _
Public Class ColGroup
    Inherits WebControl
    Implements INamingContainer

    Friend Sub RenderPrivate(ByVal writer As HtmlTextWriter)
        writer.Write("<colgroup>")
        MyBase.RenderContents(writer)
        writer.Write("</colgroup>")
    End Sub
End Class

End Namespace

This really offers you the opportunity to use it as Josh sais:

<aspcust:GridViewColGroup runat="server" ID="gridName">
    <ColGroupTemplate>
        <col class="some_class_1" />
        <col class="some_class_2" />
        ...
        <col class="some_class_n" />
    </ColGroupTemplate>
    <Columns>
        ...
    </Columns>
</aspcust:GridViewColGroup>

if you wrap the derived class into a namespace and register it in the web.config as follows:

<configuration>
    <system.web>
        <pages>
            <controls>
                <add tagPrefix="aspcust" namespace="CustomControls" />
            </controls >
        </pages >
    </system.web>
</configuration>

Programatically, you can add a new column into ColGroup at, let's say, PreRender:

Protected Sub gridName_PreRender(ByVal sender As Object, ByVal e As System.EventArgs)
    Dim grd As CustomControls.GridViewColGroup = sender
    Dim wctrl As New WebControl(HtmlTextWriterTag.Col)
    wctrl.CssClass = "some_class_m"
    grd.ColGroup.Controls.Add(wctrl)
End Sub

Cheers.

Upvotes: 3

Alex Nolasco
Alex Nolasco

Reputation: 19476

How about a minor change in order to add cols dynamically?

    /// <summary>
/// Represents a Col element.
/// </summary>
public class HtmlCol : HtmlGenericControl
{
    /// <summary>
    /// Default constructor.
    /// </summary>
    public HtmlCol()
        : base("col")
    {
    }
}

/// <summary>
/// Collection of HtmlCols
/// </summary>
public class HtmlCols : List<HtmlCol>
{
    /// <summary>
    /// Default constructor.
    /// </summary>
    public HtmlCols()
    {
    }

    /// <summary>
    /// Adds a col to the collection.
    /// </summary>
    /// <returns></returns>
    public HtmlCol Add()
    {
        var c = new HtmlCol();
        base.Add(c);
        return c;
    }
}


/// <summary>
/// Represents a colgrpup tag element.
/// </summary>
internal class ColGroup : WebControl, INamingContainer
{
    internal void RenderPrivate(HtmlTextWriter writer)
    {
        writer.Write("<colgroup>");
        base.RenderContents(writer);
        writer.Write("</colgroup>");
    }

    internal void RenderPrivate(HtmlTextWriter writer, HtmlCols cols)
    {
        writer.Write("<colgroup>");
        base.RenderContents(writer);
        foreach (var c in cols)
        {
            c.RenderControl(writer);
        }
        writer.Write("</colgroup>");
    }
}


[ToolboxData("<{0}:PlainGrid runat=server></{0}:Table>")]
public class PlainGrid : GridView
{
    private ColGroup _colGroup = null;
    private ITemplate _colGroupTemplate = null;
    private HtmlCols _cols = null;

    [TemplateContainer(typeof(ColGroup))]
    public virtual ITemplate ColGroupTemplate
    {
        get { return _colGroupTemplate; }
        set { _colGroupTemplate = value; }
    }

    protected override void CreateChildControls()
    {
        base.CreateChildControls();
        if (ColGroupTemplate != null)
        {
            ColGroupTemplate.InstantiateIn(_colGroup);
        }
    }


    protected override void Render(HtmlTextWriter writer)
    {
        // Get the base class's output
        var sw = new StringWriter();
        var htw = new HtmlTextWriter(sw);
        base.Render(htw);
        string output = sw.ToString();
        htw.Close();
        sw.Close();

        // Insert a <COLGROUP> element into the output
        int pos = output.IndexOf("<tr");

        if (pos != -1 && _colGroup != null)
        {
            sw = new StringWriter();
            htw = new HtmlTextWriter(sw);

            _colGroup.RenderPrivate(htw, _cols);
            output = output.Insert(pos, sw.ToString());
            htw.Close();
            sw.Close();
        }

        // Output the modified markup
        writer.Write(output);
    }

    /// <summary>
    /// Gets/Sets col items.
    /// </summary>
    public HtmlCols Cols
    {
        get { return _cols; }
        set { _cols = value; }
    }

    /// <summary>
    /// Default constructor
    /// </summary>
    public PlainGrid() 
    {
        base.AutoGenerateColumns = false;
        _colGroup = new ColGroup();
        _cols = new HtmlCols();
    }
}

Upvotes: 0

Josh Stodola
Josh Stodola

Reputation: 82513

I thought this was addressed in .NET 3.5, but I can't find any references. Anyways, here is a hand-rolled server control that allows you to specify colgroup...

public class ColGroupGridView : GridView
{
    private ColGroup _ColGroup = null;
    private ITemplate _ColGroupTemplate = null;

    [TemplateContainer(typeof(ColGroup))]
    public virtual ITemplate ColGroupTemplate
    {
        get { return _ColGroupTemplate; }
        set { _ColGroupTemplate = value; }
    }

    protected override void CreateChildControls()
    {
        base.CreateChildControls();
        _ColGroup = new ColGroup();
        ColGroupTemplate.InstantiateIn(_ColGroup);
    }

    protected override void Render(HtmlTextWriter writer)
    {
        // Get the base class's output
        StringWriter sw = new StringWriter();
        HtmlTextWriter htw = new HtmlTextWriter(sw);
        base.Render(htw);
        string output = sw.ToString();
        htw.Close();
        sw.Close();

        // Insert a <COLGROUP> element into the output
        int pos = output.IndexOf("<tr");

        if (pos != -1 && _ColGroup != null)
        {
            sw = new StringWriter();
            htw = new HtmlTextWriter(sw);
            _ColGroup.RenderPrivate(htw);
            output = output.Insert(pos, sw.ToString());
            htw.Close();
            sw.Close();
        }

        // Output the modified markup
        writer.Write(output);
    }
}

internal class ColGroup : WebControl, INamingContainer
{
    internal void RenderPrivate(HtmlTextWriter writer)
    {
        writer.Write("<colgroup>");
        base.RenderContents(writer);
        writer.Write("</colgroup>");
    }
}

Use it like this...

<custom:ColGroupGridView ... runat="server">
    <ColGroupTemplate>
        <col class="itemid" />
        <col class="cover-image" />
        <col class="title" />
        <col class="number" />
        <col class="year" />
        <col class="rating" />
        <col class="cgc-rating" />
        <col class="description" />
    </ColGroupTemplate>
    <!-- Rest of stuff here... -->
</custom:ColGroupGridView>

Source: Jeff Prosise's Blog

Upvotes: 6

Related Questions