views:

2035

answers:

2

I have a LinkButton inside a GridView (via an TemplateField). No matter what I try, the LinkButton will not invoke its event handler. I have tried both:

  1. A traditional event handler ("OnClick")
  2. A OnRowCommand event handler at the GridView level.

In both cases, I've debugged and it doesn't even catch the event handler.

If I move the LinkButton out on the page (so it's not in the GridView), it works fine, so I know the syntax is right.

Here is the "traditional" method:

<asp:TemplateField>
  <ItemTemplate>
    <asp:LinkButton Text="Cancel" ID="DeleteButton" CausesValidation="false" OnClick="CancelThis" runat="server" />
  </ItemTemplate>
<asp:TemplateField>

What's interesting is if I remove the "CancelThis" method from the code behind, it throws an error. So I know it's aware of its event handler, because it looks for it when it compiles.

Here is the RowCommand method:

<asp:TemplateField>
  <ItemTemplate>
    <asp:LinkButton Text="Cancel" ID="DeleteButton" CausesValidation="false" CommandName="CancelThis" runat="server" />
  </ItemTemplate>
<asp:TemplateField>

In this case, the GridView has:

OnRowCommand="GridView_RowCommand"

It postsback, but never hints at raising the event.

Any idea what I'm missing here?

A: 

Is viewstate turned on on your GridView? This has caught me out numerous times.

Brandon Montgomery
+2  A: 

How are you binding your GridView? Are you using a datasource control? If you are binding manually during Page_Load, it's possible that since the grid is binding every round trip, the event handler isn't catching properly. If this is the case, you may want to try something like:

protected void Page_Load(object sender, EventArgs e)
{
    if(!Page.IsPostBack)
    {
        //do binding
    }
}

Can you post sample binding code to go with your markup?

If you really want to force the issue, you could hook into the RowDataBound event on the Grid, find the button manually and add the handler in the code behind. Something like:

markup snippet:

<asp:GridView ID="gvTest" runat="server" OnRowDataBound="gvTest_RowDataBound" />

code behind:

protected void gvTest_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if(e.Row.RowType == DataControlRowType.DataRow)
    {
        //find button in this row
        LinkButton button = e.Row.FindControl("DeleteButton") as button;
        if(button != null)
        {
            button.Click += new EventHandler("DeleteButton_Click");
        }
    }
}

protected void DeleteButton_Click(object sender, EventArgs e)
{
    LinkButton button = (LinkButton)sender;
    // do as needed based on button.
}

I'm not sure what the purpose of the button is, but assuming it is a row delete button, you may not want to take this approach as in the event handler, you don't have direct access to the row in question, like you would using the RowCommand event.

Is there a reason you're using the Template field? Vs say a ButtonField? If you use a ButtonField, then you can hook into the RowCommand event.

markup snippet:

<asp:GridView ID="gvTest" runat="server" OnRowCommand="gvTest_RowCommand">
    <columns>
        <asp:buttonfield buttontype="Link" commandname="Delete" text="Delete"/>
        ....
    </columns>
</asp:GridView>

code behind:

protected void gvTest_RowCommand(object sender, GridViewCommandEventArgs e)
{
    if(e.CommandName == "Delete")
    {
        //take action as needed on this row, for example
        int rowIndex = Convert.ToInt32(e.CommandArgument);
        GridViewRow currentRow = (sender as GridView).Rows[rowIndex];

        //do something against the row...
    }
}

You might want to consult MSDN docs on some of these topics:

EDIT:

To answer your question on the ButtonField - yes I don't see why you couldn't still deal with a buttonfield. Here's a snippet to find the buttonfield during row data bound and hide it (untested but I think would work...)

protected void gvTest_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        //let's assume your buttonfield is in column 1
        // (you'd know this based on your markup...)
        DataControlFieldCell cell = e.Row.Cells[1] as DataControlFieldCell;
        if(cell != null)
        {
            ButtonField field = cell.ContainingField as ButtonField;

            //based on your criteria, show or hide the button
            field.Visible = false;
            //or
            field.Visible = true;
        }
    }
}
KP
Using a ButtonField, is there a way to programmatically hide or show it? I may or many not show the button, depending on some value in the current iteration. Everything I read said I had to switch to a standard Button in a TemplateField.With my current method, I'm using the RowDataBound event to examine the current iteration, find the button, and potentially hide it.
Deane
I think it would definitely be possible. Edited my answer with sample code appended.
KP