Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

ViewState and OnItemCommand on an ASP.NET Repeater


:P
On this page:

Thinking out loud here… Here's something I never noticed before: It looks like an ASP.NET Repeater doesn't fire OnItemCommand events when ViewState is off for the control. Not sure why this should be, but I'm working on a form where there are several repeaters all of which are reloaded on every.

 

I have a LinkButton control in the Repeater template with a CommandName and CommandArgument set like this:

<asp:Repeater ID="repLatestItems" runat="server"

              OnItemCommand="repLatestItems_ItemCommand">

    <ItemTemplate>

        <b><asp:LinkButton runat=server ID="lnkNewEntry" CommandArgument='<%# Eval("pk") %>' 

                           CommandName="ShowEntry"><%# Eval("Title") %></asp:LinkButton></b>

        <br />                          

        <small>

            <i><%# Eval("Entered") %></i><br />

            <%# Eval("Abstract") %>

        </small>

        <br />

        <p />

    </ItemTemplate>

</asp:Repeater>

 

With ViewState on, all works fine. Turn ViewState off and the OnItemCommand event is never fired.

 

I haven't noticed this before because in most apps I tend to use old school links instead (ie. <a href='<%# EVAL("Url")'></a> etc.)  for this sort of thing, but in this case the page has a bunch of other state that should be preserved.

 

What's interesting too is the way the __doPostback event is set up in client code, with the event argument not encoded into the function call:

__doPostBack('ctl00$MainContent$repLatestItems$ctl01$lnkNewEntry','')

Apparently ASP.NET encodes the CommandArgument into ViewState as part of the control values saved and then restores that, but why isn't it using the CommandArgument parameter to make this universally operational? Well, in theory it shouldn't need that since it can deduce the control id and from the command argument.

 

Oddly enough the same sort of thing works fine in a DataGrid/GridView which has no such issues with ViewState.

 


The Voices of Reason


 

steve
February 20, 2006

# re: ViewState and OnItemCommand on an ASP.NET Repeater

Hmmmm. In 1.1 I was wiring up a datagrid for the first time in a while and could not get the ItemCommand to fire for the grid (using Buttons) until I remembered to enable Viewstate for the grid.

You say the datagrid worked fine for you without Viewstate turned on -- now I'm really confused.

<ItemTemplate>
<asp:Button id="btnEdit" runat="server" CssClass="Button24" Text="Edit" CommandName="Edit" CausesValidation="false">
</asp:Button>
</ItemTemplate>

Wilco Bauwer
February 21, 2006

# re: ViewState and OnItemCommand on an ASP.NET Repeater

The CommandName/CommandArgument shouldn't have anything to do with ViewState. The reason that it wouldn't work without ViewState could be that you are re-binding the Repeater at the wrong moment, or you're not rebinding the Repeater at all (although in that case you shouldn't see any items at all after a postback).

Could you give some more information about the code you're trying to use?

Bill Pierce
February 21, 2006

# re: ViewState and OnItemCommand on an ASP.NET Repeater

I try to do all of my databinding in Page_Init. I've found that doing databinding in Page_Load can cause problems when disabling ViewState.

-Bill

Horses
February 21, 2006

# re: ViewState and OnItemCommand on an ASP.NET Repeater

Re-binding the grid on PostBack isn't really much of a solution, Wilco - the data being bound could well change in the time it takes for someone to PostBack; if that hapenns the control ID referenced in __doPostBack could well belong to a different data item or may not even exist.

I'm also surprised this workse with a DataGrid - I could certainly never get it to work. The DataView, on the other hand, must put this stuff in ControlState.

Rick Strahl
February 21, 2006

# re: ViewState and OnItemCommand on an ASP.NET Repeater


Of course Wilco's right. I moved some of my databinding code into OnPreRender() and that means the control isn't bound when the click is fired.

But this makes binding a pain. This means one way or another the Repeater needs to be double bound for the save operation. Once in Page_Load for all requests, and on a link to save to update with the updated values.

Not really a pain makes sense but I seem to forget this little detail more than I should in my old age <g>...

Wilco Bauwer
February 22, 2006

# re: ViewState and OnItemCommand on an ASP.NET Repeater

Horses: You are right in saying that a different LinkButton in a different row may raise the event. That's part of the reason why you use the CommandName/CommandArgument instead of relying on an index.

Ofcourse, this would fail when you clicked on say the link of the second item, and when you postback there is only 1 item left (because someone else removed an item). It would fail because the Page will be unable to find the clicked control, because it is no longer re-created by the Repeater.

Instead of disabling the ViewState on the Repeater, you might want to try and disable the viewstate of all child controls instead (eg. place them in a PlaceHolder and disable it's ViewState). In that case the Repeater will re-create the items on a postback, and the events should raise as expected. You should then be able to re-bind in the PreRender phase (ofcourse, make sure you _always_ rebind in the PreRender). Keeping the ViewState of the Repeater itself enabled should not be an issue, since I believe all it stores in the ViewState is the item count. In my opinion, this item count should really be stored in the ControlState instead, for exactly this scenario. If it would be part of the ControlState, you could simply disable the ViewState on the Repeater.

Horses
February 23, 2006

# re: ViewState and OnItemCommand on an ASP.NET Repeater

The problem is that, on PostBack, the CommandName/CommandArgument relevant to the button that was clicked are determined by looking at the ID of the LinkButton.

Say you have three Items in your repeater:

Billy Ocean (ID:ctl1, CN:Edit, CA:190)
Lionel Richie (ID:ctl2, CN:Edit, CA:23)

Before someone has a chance to click on Lionel Richie's edit button, someone else using the site has added another choice singer to the list - Feargal Sharkey.

When the page is postback and the repeater re-bound, the contents will now be like this:

Billy Ocean (ID:ctl1, CN:Edit, CA:190)
Feargal Sharkey (ID:ctl2, CN:Edit, CA:200)
Lionel Richie (ID:ctl3, CN:Edit, CA:23)

When the Command/Click event is raised, the framework will see that ctl2 was clicked and will base the CommandName/CommandArgument on whatever has the ID of ctl2, which is now Feargal Sharkey rather than Lionel Richie, which was clicked.

As Rick says, this is because __doPostback does not contain the command argument or name, just the ID of the control.

Wilco Bauwer
February 23, 2006

# re: ViewState and OnItemCommand on an ASP.NET Repeater

Horses: Interesting. I thought it would actually render the command argument, but you're right that it doesn't. You could inherit from LinkButton, override the GetPostBackOptions method and make sure the returned options do have the Argument set, but obviously this is far from ideal. IMO controls such as the LinkButton should take care of rendering the command argument in cases like these.

Thanks for the heads up.

Rick Strahl
February 23, 2006

# re: ViewState and OnItemCommand on an ASP.NET Repeater

Great discussion. This is exactly the kind of thing I run into from time to time. There are so many different details of how controls bind back data and where it comes from that it's real hard to keep track. A lot of time ends up being wasted on trial and error figuring out just exactly why a value isn't there.

It doesn't help if you're doing this (as I did when I wrote this up) at 3 in the morning <g>...

Fabian
April 24, 2006

# re: ViewState and OnItemCommand on an ASP.NET Repeater

Great Article, thanks!

MichaeS
June 09, 2006

# re: ViewState and OnItemCommand on an ASP.NET Repeater

Rick,
I read this discussion with great interest but still have a problem with Repeater and LinkButton inside. These two are sitting in the UserControl that has EnableViewState="false" (I tried to enable it but then it complains that the control is not serializable). I set EnableViewState="true" on both Repeater and LinkButton, but still OnItemCommand is not fired. Any suggestions?

# DotNetSlackers: ViewState and OnItemCommand on an ASP.NET Repeater


Siderite
November 01, 2006

# re: ViewState and OnItemCommand on an ASP.NET Repeater

I am having a really weird day. I tried to move a site from 1.1 to 2.0 and it basically worked, until I noticed that linkbuttons in a datagrid (not a gridview) did not keep their commandargument and commandname properties on postback.

The code is a simple datagrid with a template column that has a linkbutton and the CommandArgument, CommandName , Text and Enabled properties are set as '<%# Bind('stuff') %>'.
I have no idea what is going on!
I mean, it goes into the onItemCommand or onClick or whatever, it does show the correct control as e.CommandSource, but the CommandArgument and CommandName properties are empty. The Text or Enabled properties are both ok.

ViewState is ON on the page, on the Datagrid and even on the linkbutton. If I replace the LinkButton with a Button the same thing happends.

ASP.NET Forums
June 11, 2007

# Reducing Viewstate for a Repeater Control - ASP.NET Forums


Md Sarker
September 02, 2007

# re: ViewState and OnItemCommand on an ASP.NET Repeater

I am facing the same problem also, but with a datalist. LinkButton on ItemTemplate does work fine. But Update and Cancel buttons located inside the EditItemTemplate doesn't fire at all. I am digging through Google all day today. No luck.

Md Sarker
September 02, 2007

# re: ViewState and OnItemCommand on an ASP.NET Repeater

Forgot to mention one more thing. Page had EnableViewState=false.
Also NO BUTTON events get fired from edititemtemplate. not even OnClick. But if you put them on itemTemplate works just fine.

Mohamed Rashwan
September 19, 2007

# re: ViewState and OnItemCommand on an ASP.NET Repeater

I have a sort funcionality for the repeater. When I rearrange the items, they get displayed right, but the CommandArgument remains the same with no effect from sorting!

Andy Bruce
October 21, 2008

# re: ViewState and OnItemCommand on an ASP.NET Repeater

OK--this is an ancient post. But I ran into exactly the same thing this morning on a SharePoint project using SmartPart and lots of other "stuff". That is--setting up ItemCommand on a simple repeater just didn't freakin' fire.

After *much* experimentation (viewstate on, viewstate off, checking eventtarget, doing unique ID lookup at page load to manually fire event, and much more) here was the skinny--it wasn't viewstate at all. Rather, the stupid repeater control is (apparently) reloading the control set after my initial data bind.

This is still (I'm sure) some silly interaction between SP and viewstate, but here's the timeline:

1. SmartPart hosts ASCX control.

2. My hosted ASCX control is a tabbed page, so I dynaload the tab pages (if I'm not in page editing mode).

3. In my dynaloaded tab page, in OnInit I do a databind. (I have to do this regardless of viewstate, I suspect it's an artifact of me adding controls to the page dynamically.)

4. All the normal databinding fires on my repeater. The RepeaterItem (rows) objects all have auto-generated IDs. (Hint: That's the real problem...)

5. Check on the generated source and I see that the unique IDs being created for the LinkButton elements show a *different* unique ID for the RepeaterItem. That is--when the first RepeaterItem was initially created during my explicit data bind its name was "ctl01". The LinkButton's unique ID should be "[...]$ctl01$lnkbtn". However, on the generated source I see "[...]$ctl06.lnkbtn". There are three repeater items--I believe what's happening is that (somewhere!) my explicitly-generated three rows are being replaced and new RepeaterItem entries being created--three times!

The problem was this--because at Page_Load time the *current* generated unique ID for the link button on, say, row 3 is *different* than the unique ID being passed as __EVENTTARGET. So ASP.NET can't match the control IDs, so the event doesn't fire. Sheesh...

6. To hack around this problem: a) Created class variable int _itemNumber. b) Override repeater's DataBinding and set _itemNumber to zero. c) Override ItemCreated and set the e.Item.ID to "c" + _itemNumber.

The net effect is that regardless of how many times my repeater items (rows) are (re)created, they will always have the same ID. On checking the UniqueID in the page source I see that each of my three link buttons have "[...]$c1$lnkbtn" "[...]$c2$lnkbtn" and "[...]$c3$lnkbtn" respectively. On Page_Load I see that __EVENTTARGET has that UniqueID properly set. And since ASP.NET can now match up __EVENTTARGET to a real-honest-to-goodness LinkButton I see that everything is A-OK (including receiving CommandName and CommandArgmument as part of ItemCommand event args).

Moral--1. Understand why ASP.NET is "recreating" my repeater rows (nope, don't know that one yet). So better moral--2. Go out of your way to make sure that IDs for dynamic controls are always created properly (that is, set the ID explicitly if you possibly can). Things just tend to work better...

Matt
February 11, 2009

# re: ViewState and OnItemCommand on an ASP.NET Repeater

I am experiencing similar problems since I upgraded to 3.5 sp1. In a Datalist, after the linkbutton OR imagebutton is clicked, the itemcommand even is not fired - the view state appears empty - even though enableviewstate = true.

The same code works perfectly in 2.0 - appararently with 3.5 sp1, there is an update for 2.0 also which breaks my code.

Does anyone understand what might have changed and how I can get the itemcommand firing around with 3.5 sp1?

Please post comments here and email me if possible (matt .at. newreflectionscounseling.com)

Michael
June 14, 2009

# re: ViewState and OnItemCommand on an ASP.NET Repeater

This is one of the most interesting threads. Hope, I can shed some light on the process. (.Net 3.5 SP1)

I'm working on the page where GridView is dynamically created and it has one of the columns as ImageButtons with CommandArgument used to pass PK of the record. So, I found that in my case I have to recreate GridView object with exactly the same ID and set of rows (emty ones do just fine) in order to get gridRowCommand event fired with correct command argument. It looks like .Net runtime needs the rows to match automatically generated control ID for the clicked button and then it uses ViewState to pass the CommandArgument value. It actually passes CommandArgument values for every row but only one which was clicked is used. It determines which one was clicked by looking at the Request.Form collection.

So, if I re- create my dynamic grid with correct number of rows but set EnableViewState for the whole page to false the event gets fired but the CommandArgument is null as it wasn't passed around.

maxdmvp
June 25, 2009

# re: ViewState and OnItemCommand on an ASP.NET Repeater

In the past I've used your posts and I've found them very useful but until now I didn't take the time to say thanks. Today I'm specially grateful as I was running out of ideas with this problem. Thanks for documenting your findings.

muruganad
November 03, 2009

# asp .net repeater control pass commandargument OnItemCommand


Joopa
December 11, 2009

# re: ViewState and OnItemCommand on an ASP.NET Repeater

Murugan, that's just the normal button handling with Repeater itemcommand.
This article is discussing about ItemCommand not firing when EnableViewState is set to false.
Try your own sample with ViewState disabled...

john h.
February 16, 2010

# re: ViewState and OnItemCommand on an ASP.NET Repeater

If you call DataBind() elsewhere in your site, such as in a master page, then it may erase the data in your repeater. This may be the trouble some people are seeing.

jon k
June 23, 2010

# re: ViewState and OnItemCommand on an ASP.NET Repeater

aaah john h. i could kiss you!

I've been banging my head against this wall for nearly half a day now got to the point where i'd wired up handlers for OnDataBinding, OnItemDataBound and OnItemCreated for the repeater and wondered why the hell OnDataBinding was firing once before I'd ever called DataBind() on it.

You're exactly right in my case: I was adding a control to a page on a site I built a few years ago, back in the days when I thought it was a good idea to sprinkle <%# PagePublicVariable %> around the markup and call Page.DataBind() to fill them all up.

Now I've taken that Page.DataBind() sucker out and sanity is returning. Thanks again (and thanks Rick for hosting this most excellent 4-year-spanning conversation!)

Jørgen Helgheim
May 05, 2012

# re: ViewState and OnItemCommand on an ASP.NET Repeater

The answer is to use the new ListView control. Listview does not require a databind to trigger det itemcommand event. It preserves the commandargument, commandname and even has a commandsource property, which holds the reference to the linkbutton clicked.

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024