views:

643

answers:

2

I have a (derived) Menu control, that displays a rather large list of items from a custom data source. I need to disable ViewState on the menu to avoid the very annoying "Can't select a disabled or unselectable menu item" when some other control causes the current selection to change on a postback.

Unfortunately, when ViewState is disabled for the Menu, the postbacks generated by the menu aren't raising any events. If I enable ViewState, the OnMenuItemClick event is raised. If I disable ViewState, OnMenuItemClick is not raised. I'm perplexed.

I need to leave ViewState off for the menu, so how can I handle postbacks from the actual menu?

At this point I'm leaning towards using the Menu's Load event, parsing the __EVENTTARGET to see if it's the Menu, and going from there. This would technically process the postback event before it would normally but that's ok, I guess.

Any better ideas?

A: 

I've figured out the essence of the problem. Using Reflector we can see the important part(s) of the low level method that handles the actual postback and then raises the event:

string str = HttpUtility.HtmlDecode(eventArgument);
...
MenuItem item = this.Items.FindItem(str.Split(new char[] { '\\' }), 0);
if (item != null)
    this.OnMenuItemClick(new MenuEventArgs(item));

As you can see the MenuEventArgs is handed a MenuItem. If one cannot be found in the current Items collection that matches the incoming post data, then the event is not raised. With ViewState disabled, the menu doesn't have any Items (they would have been rebuilt using ViewState). So the event won't be raised.

To work around this, I've told the menu to build itself during Load using the not-yet-updated data (at this point it will be the same as it was at the end of the last request). This is essentially the same as rebuilding the menu from ViewState, so I don't feel bad in regards to performance, or whatever. OnMenuItemClick is then fired as expected. Lastly, during PreRender I tell the Menu to rebuild once again, so it reflects the changes that happened during the postback processing portion of the lifecycle.

I wasted a lot of time on this, so hopefully this info can help somebody else in a similar situation.

sliderhouserules
+1  A: 

Yep, you can choose, either use viewstate to repopulate a bound control or you can databind it before events are fired (Page_Load is fine).

I wouldn't necessarily always bind it afresh in Page_PreRender though, if nothing has changed on this postback (changes happened somewhere else on the page) then there is no reason to bind it again.

Instead you might be able to bind only on certain events when you know it will have to change.

AndreasKnudsen
Good suggestion, I'll keep that in mind.
sliderhouserules