It seems that the ImageButton has few major issues, especially when nested within other controls like the GridView. Please find references to issues regarding firing events twice because of the ImageButton.
The issue I faced lately was caused by the ImageButton nested in a TemplateField of the GridView. But instead of firing the event twice, the ImageButton caused the event to vanish!
<asp:ImageButton ID="imgEdit" runat="server" ImageUrl="~/Resources/item_detail.gif"
CommandName="itemedit" CommandArgument='<%# ((CustomObject)Container.DataItem).Oid %>' />
In theory the CommandName defined on such ImageButton should fire RowCommand on GridView. And it does so, except at least one specific scenario where the GridView is dynamically loaded at each postback.
In such case, the GridView is automatically filled with the data from the datasource. But when another control forces it to rebind, the ImageButton stops to fire the event.
The bug is obvious - it is sufficient to replace the ImageButton with the LinkButton and the event is fired correctly.
<asp:LinkButton ID="imgEdit" runat="server"
CommandName="itemedit" CommandArgument='<%# ((CustomObject)Container.DataItem).Oid %>'>
<asp:Image ID="imgEditImage" ImageUrl="~/Resources/item_detail.gif" ToolTip="" runat="server" />
</asp:LinkButton>
Note that however both declarations provide the same visual output, the ImageButton is renreded as <input type="image" ... > while the LinkButton is rendered as <a onclick="javascript:__doPostBack(...)"><img src="..."></a>.
This difference does not mean much to the user but seems to be crucial for this to work correctly.