Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why won't my LinkButton inside a GridView raise its OnClick event?

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?

like image 732
Deane Avatar asked Feb 02 '10 17:02

Deane


1 Answers

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:

  • RowCommandEvent
  • ButtonField class

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;
        }
    }
}
like image 199
KP. Avatar answered Oct 07 '22 15:10

KP.