Monday, January 14, 2008

ImageButton in the TemplateField does not fire RowCommand

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.

16 comments:

xazos79 said...

Cheers for this! Unfortunately LinkButton still doesn't fire the event for me either. My breakpoint never gets hit.

Wiktor Zychla said...

I confirm two or three cases where the Click event is lost somewhere for good. In such cases, I tend to go as "low level" as possible: check the Request.Form collection of posted values in the Page_Load event. this way you will ALWAYS know what is the cause of the postback. Use this trick with care however because once you know that everything ultimately sits in the Request.Form, you soon become addicted to it.

venky said...

Hai
Actually i want to keep css class in image button in Template field .css class contains an image

Tomalak said...

I've been banging my head over this irritating problem the whole day, to no avail.

As it turns out, events are lost when ViewState is disabled for my GridView control. As soon as I enable ViewState, it works like charm.

But enabling ViewState is not what I want, what does that have to do with event handling?

To me, this is clearly a bug.

Wiktor Zychla said...

I belive that some events can ONLY be raised with viewstate turned on (for example the TextChanged event).

this however does not explain why many other events are gone in variety of scenarios.

Tomalak said...

I understand that specific events depend on knowing the previous state of a control.

But clicking an ImageButton to provoke a form postback clearly indicates the source of the event to the server, regardless of ViewState. It's a FORM submit, after all.

For me there is no valid reason to let half the database make a server round trip in ViewState, when the GridView is populated with fresh read-only data every time anyway. Thats just useless bloat.

People seem to be conditioned to use ViewState up to the point that I could not find any indication that disabling it in a GridView may impact event triggering - until I found out myself and searched for it specifically, that is. Even the VS documentation does not mention it.

Wiktor Zychla said...

I absolutely agree. In specific cases, when the conversion of ImageButton to LinkButton is not an optin, we are forced to manually handle postbacks by referring to Request.Form.

events just do not work and nothing can be done about it. most often it is caused in our appliaction by inserting grids dynamically to the page in every postback. all other events usually work properly but the click event does not work.

Anonymous said...

thanks for this. LinkButton works for me.
And I get the same result when I use [linkbutton][img][/linkbutton] compared to [imagebutton /], so that might be a usable workaround for everyone who is facing this problem

Echilon said...

This definitely appears to be a bug. I've tried both methods you suggested but no luck. :(

Nic said...

Seems related to behaviour of standard html controls in an update panel.

LinkButton is rendered as a link which uses javascript to post data back to the server.

ImageButton is rendered as a standard html input, which uses html postback to communicate with the server.

Actually makes sense that you need javascript for AJAX communication.

Anonymous said...

You can use an image button in a gridview and cause the row_command event to fire. Use the OnClientClick event for the ImageButton when it is in a template field andn then use only the gv_rowcommand event and in the event do what you would like to do.

VB.NET
Gridview_RowCommand Event
If e.CommandName = "EditButton" Then
'Do Stuff
End If
End Sub

THIS WORKS 100% of the time!

Tony Anonas said...

Well, on my case the asp:button works out fine in alternate for the LinkButton control. Sounds weird ? ei?

Anonymous said...

I have a similar problem that I can't get around. A Repeater with image buttons, and when clicked the event handler fires. I've added 'Compare' checkboxes to the items to narrow the list and this works fine, but when clicking an imagebutton from this list the event won't fire! It works when I use a hyperlink, but I need some event handling. It's driving me loopy!!!

Ewak said...

I was having the exact same problem.

So based on your post I chucked an Image control into a LinkButton to replicate the look and feel of an ImageButton, and it works perfectly.

Anyway, thanks for posting!

Mikw said...

I GOT A FIX FOR THIS.

in the page load

if(!isPostBack)
{
//bind the data
}

worked for me

Emiliano said...

Hi, I hope someone will serve, in my case at implementation on IIS (virtual directory) was off the ViewState in section of the web.config file in the root directory with major hierarchy.
Enabling ViewState in virtual directory's web.config solved the problem for me.