Get Text of Hyperlink which is sitting inside template field in a gridview

asp.netgridviewhyperlinktemplatefield

Seems to be easy but I am having a hard time with this.

    <asp:TemplateField HeaderText="ID" InsertVisible="False" SortExpression="id">
        <ItemTemplate>
            <a href="/visit.aspx?Id=<%#Eval("Id")%>" id="ID" name="ID">  <%#Eval("Id")%> </a>
        </ItemTemplate>
    </asp:TemplateField>

There is a button in the last column of gridview. Click this button updated the database and refreshed gridview. It also look at the id column in gridview and tries to highlight the row that was edited.

The code works without any problem if ID field is bounded field and is not a URL. But when it is a URL, I cannot seem to read the text value of the URL. I have tried various solution (help from SO and online)

HyperLink link = (HyperLink)row.FindControl("id"); // did not work

((HyperLink)GridView1.Rows[i].Cells[0].Controls[0]).Text // did not work

This is the code snippet that I need help with

            for (int i = 0; i < GridView1.Rows.Count; i++)
            {
                GridViewRow row;
                row = GridView1.Rows[i];
                if (row.RowType == DataControlRowType.DataRow)
                {

                    HyperLink link = (HyperLink)row.FindControl("id");
                    if (((HyperLink)GridView1.Rows[i].Cells[0].Controls[0]).Text == button.CommandName)
                    {
                        row.BackColor = System.Drawing.Color.IndianRed;
                     }
                }
            }

I am using button.CommandName to store the ID field which works fine. I just can't seem to find the hyperlink control in the gridview inside a template field.

I am getting the following error which does not make sense to me

Unable to cast object of type 'System.Web.UI.DataBoundLiteralControl'
to type 'System.Web.UI.WebControls.HyperLink'.

Update1
This code works without hitch, if I do not use hyperlink field.

 for (int i = 0; i < GridView1.Rows.Count; i++)
                    {
                        GridViewRow row;
                        row = GridView1.Rows[i];
                        if (row.Cells[0].Text.Equals(button.CommandName))
                        {
                            row.BackColor = System.Drawing.Color.IndianRed;
                        }
                    }

If change the column 0 to hyperlink and change the code corresponding, then it does not work. Clearly reading the wrong cell is not the problem.

for (int i = 0; i < GridView1.Rows.Count; i++)
{
    GridViewRow row;
    row = GridView1.Rows[i];
    HtmlAnchor anchor = (HtmlAnchor) row.Cells[0].Controls[0];
    if ( anchor.InnerText.Equals(button.CommandName))
    {
        row.BackColor = System.Drawing.Color.IndianRed;
 }
                }

Best Answer

First things first - you are trying to FindControl("id"); where your control in the design view is actually ID - Case matters.

Another thing - this also appears to be because <a> isn't actually a HyperLink control, but actually a HtmlGenericControl - thus trying to cast your control is resulting in nothing.

You could do one of two things - change your code-behind to get HtmlGenericControl link = (HtmlGenericControl )row.FindControl("ID");

Or change your design view and use an <asp:Hyperlink> control instead of the HTML <a>

Your error Unable to cast object of type 'System.Web.UI.DataBoundLiteralControl' (which is ain HTML terms) to type 'System.Web.UI.WebControls.HyperLink'.

Is saying ((HyperLink)GridView1.Rows[i].Cells[0].Controls[0] that the control at position 0 in the first cell on the row your processing is a literal and NOT a link. You can try to fudge it by looking at Controls[1] instead.

you can view the rendered HTML of your table and verify this - your link will be nested in a span, or next to a span..

Examine the Controls in debug and see what is actually contained in it.

Update

There is a lot of confusion over HOW your calling your code. You have e.Row.RowType which leads me to believe you're doing this in RowDataBound.

If this is the case then you do NOT need to loop through all of your gridview rows as this method gets called on every row - so you would be calling each row, then each row in the grid.. MASSIVE amount of looping going on for a big grid.

So try this instead - it is only interested on that one row.

also - not sure where you;re getting your button.CommandName from

For this you will need to examine your FindControl method to make sure it actually IS a hyperlink control

if ((e.Row.RowType == DataControlRowType.DataRow)) {
    GridViewRow row = e.Row;
    // get your link - if indeed the control IS a hyperlink
        // this will be null if the control "id" is NOT a hyperlink control
    HyperLink link = (HyperLink)row.FindControl("id");
    if ((link.Text == Button.CommandName)) {
        row.BackColor = Drawing.Color.IndianRed;
    }
}

last update...

Ok - after more comments I reckon you need to recursively search for the control. this is because FindControl will only look at the direct controls within a control. it will not find controls within controls within your control - I.E FindControl looks at the first children only and not grandchildren.

So create this method where ever you like:

public static Control FindControlRecursive(Control Root, string Id)
{
    if (Root.ID == Id) { return Root; }

    foreach (Control Ctl in Root.Controls)
    {
        Control FoundCtl = FindControlRecursive(Ctl, Id);
        if (FoundCtl != null) { return FoundCtl; }
    }
    return null;
}

Then pass in your row and the ID of the control you're looking for.

So like this - change:

 HyperLink link = (HyperLink)row.FindControl("id");

to this - notice i kept your lowercase id - not sure if you are using lowercase or uppercase - this method will hunt out the little bugger for you :)

Control link = FindControlRecursive(row, "id");

Once you have your control you can cast it to what you need/or it should be

Related Topic