Alex Zhukovskiy
Alex Zhukovskiy

Reputation: 10015

GridView change headers text

Complexity is that grid should have AutoGenerateColumns = true. I cannot use TemplateField etc, so no aspx, only .cs file manipulations are allowed. Requirements:

I dunno when Asp.Net fills a header row, but he do it deep inside, because when PreRender, RowDataBound etc rise, header row still be empty. If I rename it, it works, but in this case Asp.Net renders it as plain text. Okay, i'm hardcoding postback url and retrying, but no success, this code

private void FillHeaders()
{
    const string linkText = @"<a href=""javascript:__doPostBack('ctl00$PlaceHolderMain$AuditGridView','Sort${0}')"">{1}</a>";
    bool a = true;
    if (a)
        for (int i = 0; i < LanitAudit.Properties.Length; i++)
        {
            AuditGridView.HeaderRow.Cells[i].Text = string.Format(linkText, LanitAudit.Properties[i].Key, LanitAudit.Properties[i].Value);
        }
    }
}

rises an exception:

Invalid postback or callback argument. Event validation is enabled using in configuration or <%@ Page EnableEventValidation="true" %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validation.

I still hope that i can not use client-side JS.


Tnx for answers, but probably my question is malformed. Yes, I can replace header text, BUT after it I cannot sort gridview (see 2nd requirement). Screen is below. As u see, I cannot click New Header Text, it's plain text. But if I try to use __doPostBack myself, i get an error you can see above. enter image description here

Upvotes: 0

Views: 2531

Answers (3)

Alex Zhukovskiy
Alex Zhukovskiy

Reputation: 10015

I found that the single way to change HeaderRow is manipulate Column.HeaderText property (using GridView.Columns collection). GridView.HeaderRow is useless at all. This is why i decided to abandon column autogeneration. So - why not write it myself? This code worked for me:

    public override void DataBind()
    {
        if (AuditGridView.Columns.Count == 0)
            foreach (var pair in LAudit.Properties)
            {
                AuditGridView.Columns.Add(new BoundField
                                          {
                                              DataField = pair.Key,
                                              HeaderText = pair.Value,
                                              SortExpression = pair.Key
                                          });
            }
        base.DataBind();
    }

we disabling AutoGeneratedColumns, and generating them ourselves. LAudit Properties is just array of KeyValuePair (i'm using it instead of Dictionary, because order is important). My realisation is:

    static LAudit()
    {
        var keys = typeof (LAudit).GetProperties(BindingFlags.Public | BindingFlags.Instance).Select(x => x.Name).ToList();
        string[] values =
        {
            "Prop1", "Prop2", "Prop3", //...
        };

        Properties = new KeyValuePair<string, string>[keys.Count];
        for (int i = 0; i < Properties.Length; i++)
        {
            Properties[i] = new KeyValuePair<string, string>(keys[i], values[i]);
        }
    }

    public static readonly KeyValuePair<string, string>[] Properties;

It's naive, perhaps, should use LINQ join or something else, but principe still be the same.

Hope it will be helpful.

Upvotes: 1

Josh Darnell
Josh Darnell

Reputation: 11433

If you wait until the GridView is databound, you can just access the HeaderRow property to make whatever changes you need:

protected void AuditGridView_DataBound(object sender, EventArgs e)
{
    AuditGridView.HeaderRow.Cells[0].Text = "New Header Text";
}

You have to wait until at least the DataBound event, because the content of the GridView hasn't been finalized before that point. See this note from the HeaderRow docs on MSDN:

Any modification to the HeaderRow property must be performed after the GridView control has been rendered; otherwise, the GridView control will overwrite any changes.

Note: gmd's answer also works, since he's waiting until at least the HeaderRow is rendered before making changes to it


If this is breaking the link, just change the part of the text that you need to change by parsing the values. It's kind of tedious, but if that's what you're stuck doing, this is how to do it:

protected void AuditGridView_DataBound(object sender, EventArgs e)
{
    string newLinkText = "New Header Text";

    string headerText = AuditGridView.HeaderRow.Cells[0].Text;
    string linkText = ExtractLinkTextFromHeader(headerText);

    AuditGridView.HeaderRow.Cells[0].Text = headerText.Replace(linkText, newLinkText);
}

private string ExtractLinkTextFromHeader(string headerText)
{
    int linkStartIndex = headerText.IndexOf('<');
    int linkEndIndex = headerText.IndexOf('>', linkStartIndex);

    return headerText.Substring(linkStartIndex, linkEndIndex - linkStartIndex);
}

Upvotes: 1

GMD
GMD

Reputation: 761

Try this, below is changing for 1st column og grid on RowDataBound event of grid.

protected void gv_RowDataBound(object sender, GridViewRowEventArgs e)
{
  if (e.Row.RowType == System.Web.UI.WebControls.DataControlRowType.Header)
  {
     e.Row.Cells[0].Text = "test";
  }
 }

See changes below, it may be what you are trying to do.

protected void gv_RowDataBound(object sender, GridViewRowEventArgs e)
{
  if (e.Row.RowType == System.Web.UI.WebControls.DataControlRowType.Header)
  {
      //e.Row.Cells[0].Text = "test";

      LinkButton lnk1 = e.Row.Cells[0].Controls[0] as LinkButton;
      lnk1.Text = "test";
  }
}

Upvotes: 2

Related Questions