Its an EventValidation issue. This also occurs only with an ImageButton nested in a gridview.
protected void Page_Load(object sender, EventArgs e)
{
//if (!IsPostBack)
//{
BindGrid();
//}
}
private void BindGrid()
{
ArrayList al = new ArrayList();
al.Add("a");
al.Add("b");
al.Add("c");
GridView1.DataSource = al;
GridView1.DataBind();
}
protected void ImageButton1_Click(object sender, EventArgs e)
{
}
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server"
OnRowDataBound="GridView1_RowDataBound">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<asp:ImageButton ID="ImageButton1"
OnCommand="ImageButton1_Click" runat="server" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
</form>
</body>
</html>
As you can see from the following sample code, we are rebinding our grid even on a postback, this means when the user posts back via our ImageButton, the grid will get rebound again. When this happens the gridview will recreate the gridview Vs pulling values from viewstate. By calling DataBind again in the page_load method, the Gridview recreates the child controls, and by the time our page gets to the Postback event handling phase, RaisePostBackEvent is fired in our imagecontrol(since it implements the IPostBackEventHandler interface).
RaisePostBackEvent is what calls the ValidateEvent method, with two arguments. 1st argument is the UniqueID of our ImageButton and the second argument is a string argument. The issue here is with the UnqiueID argument. It has the id of the wrong control. Since the gridview is a templated control, it prefixes the control with a unique namespace which happens to be the rowID of the current row which gets appeneded along with the gridview's id. Its this row id going wrong somehow only during RaisePostBackEvent.
You can try setting a unique id for the row generated by the ItemTemplate in our gridview. YOu can try this in either the RowCreated method or the RowDataBound method. In this manner we do not depend anymore on INamingContainer generating a uniqueID for the row, which in turn gets prefixed on our control since the row is now the direct NamingContainer and the problem is solved, eg :
protected void GridView1_RowCreated(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
e.Row.ID = e.Row.RowIndex.ToString();
}
Few solutions over the internet states applying if(!IsPostBack) will resolve the issue, true, but only in case if you do not want to re-bind your grid on editing a row as well. If you want to rebind grid after deleting a record with the help of ImageButton and rebind it after editing a row as well then you need to apply the above solution which perfectly works for both the scenarios.