Nested datagrids -- events not handled correctly

S

Steve Hershoff

Hi everyone,

I've got a strange one here. There are two datagrids on my page, one nested
within the other. I'll refer to them as the topmost and secondary
datagrids.

In the topmost datagrid's OnItemDataBound() method we check for the row in
which it's appropriate to add the secondary datagrid. Exactly one row in
the topmost grid will contain the secondary grid.

When we do find the appropriate row in the topmost grid, we add to one of
its cells a DropDownList and then our secondary datagrid. Meanwhile, within
this secondary datagrid we add a LinkButton to one of its cells, for
specific rows. Not all rows of the secondary grid get a button. We use the
ItemEvent() method to check.

When we add the DropDownList and LinkButtons, we create event handlers for
their SelectedIndexChanged() and Click() events, respectively. Now comes my
problem.

What's strange is that when I click on one of the LinkButtons the page is
reloaded (as expected), but then the DropDownList's SelectedIndexChanged()
handler is fired. I never touched the DropDownList however.

What's more, if I fail to call the secondary datagrid's DataBind() method
from within this DropDownList event handler, the LinkButton's Click()
handler is never called-- even though that's the control I clicked on to
start the chain of events!

So I'm confused to say the least. I realize this stuff can be tricky and
I'm not expecting a total answer to my problem, but does any of this ring a
bell? Specifically, why is the DropDownList's event handler being fired
when the LinkButton is clicked, and why is the LinkButton's Click() handler
never called unless the DropDownList's event handler calls the secondary
datagrid's BindData() method?

Thanks very much.
 
T

Tim_Mac

hi steve,

here is a good article on this re-occuring question:
http://odetocode.com/Blogs/scott/archive/2006/07/19/5365.aspx

when you create a control programatically like you do in your code, you need
to fully re-create it for each postback. otherwise your event is going to
be raised for a control that doesn't exist, since each post back is its own
separate entity. this is why the click event doesn't happen unless you
re-bind the datagrid.

strange that the SelectedIndexChanged event is fired, did you try debugging
to see what the call stack is like when that event is triggered. this will
help you track whether it is in response to some of your own code. can you
post your code for databinding the drop down list?

tim
 
S

Steve Hershoff

Hi Tim,

Thanks for your note, and for the links. When the SelectedIndexChanged
event is fired it's the only element in the call stack, aside from the
ubiquitious <Non User Code> portion below it.

Here's the code used for creating the dropdown. It's called in the OnInit()
method of the web control (this is all contained in an ascx file):

this.ddl_Transaction_Filt = new DropDownList();
this.ddl_Transaction_Filt.Items.Add(new ListItem("Taken", "TAKEN"));
this.ddl_Transaction_Filt.Items.Add(new ListItem("Accrued", "ACCR"));
this.ddl_Transaction_Filt.Items.Add(new ListItem("Adjusted", "ADJ"));
this.ddl_Transaction_Filt.Items.Add(new ListItem("All", "ALL"));
this.ddl_Transaction_Filt.CssClass = "Normal";
this.ddl_Transaction_Filt.AutoPostBack = true;
this.ddl_Transaction_Filt.SelectedIndexChanged += new
System.EventHandler(this.ddl_Transaction_Filt_SelectedIndexChanged);

....as you can tell, the dropdown is hard-coded.

Here's something interesting: later on in the OnInit() method I compare a
session variable with the value in that dropdown list. If the session
variable and the value in the dropdown differ I set the index in the
dropdown appropriately.

The guy who worked on this page before me made a mistake in the code and
mixed up the "ADJ" and "ALL" bits. The result being the dropdown's index
changes on every page load, which means the secondary datagrid is bound
every page load, which also means (it appears) the LinkButton's click event
is handled when needed. If I "fix" his code so the dropdown works correctly
the LinkButton no longer works.
 
T

Tim_Mac

hi steve, i'm trying to piece together the setup there.

so the drop-down-list SelectedIndexChanged event fires because of your code
that compares the session variable and updates the SelectedIndex of the menu
accordingly. that one is explained then?

if you only bind the secondary datagrid in response to a
SelectedIndexChanged event, then the LinkButton Click event won't fire for
that datagrid. you need to bind the secondary datagrid for each post back
where you want to use events with it (especially on the Postback that occurs
when you click the LinkButton).

you're code should look something like this:

public void Page_Load(...)
{
if(!IsPostBack)
{
// bind the topmost datagrid and other first time load stuff
}
else
{
// bind the secondary datagrid, dropdownlist, extra button
column, etc.
// exactly as you had it as of the last postback
}
}

this approach works for me. if this doesn't give you any ideas, can you
post your Page_Load and OnInit code, and anything else that affects the
loading/binding of the dynamic controls. if it's worth it, you may like to
create a stripped down version of the page and i could test it out here.

cheers.
tim
 
S

Steve Hershoff

Thanks again Tim. You understand how the dropdown list and the session
variable interact.

I guess I need to play around a little more. I suppose the way things work
is that when I click the LinkButton a postback is generated, then the
Page_Load is called. I assumed the LinkButton's Click() event handler would
be called even if the datagrid it resides in isn't bound again, but it
appears not?

One more thing, if you don't mind another question. Would you happen to
know what events are fired or what happens in general on a page when a
DataBind takes place? I ask because in our Page_Load we're binding the
topmost datagrid every time, whether IsPostBack is true or not.

The first time we enter this page the topmost grid is bound only once. If I
click on a hyperlink to "show the secondary datagrid," the Page_Load method
is called again, with IsPostBack set to true. So far so good. Again,
Page_Load binds the master datagrid.

However, this time the page is immediately reloaded(?) (IsPostBack equals
false now) and the master datagrid is bound yet again. Only now is the
secondary datagrid loaded and bound.

I don't understand why Page_Load is called twice in succession? I'm not
reloading or redirecting back to the page, at least not directly in my code.
Strange indeed.

I keep trying to find good information on the page lifecycle. The
4guysfromrolla.com site is great for workaday questions involving aspx, but
it's still tough. No two sources seem to agree on what happens. Either
that or they flood you with terms like PagePreRenderInit() and set your head
spinning. Do you happen to have any favored websites or books that do a
good job on this?

Thanks again for all your help. I really appreciate it.

-Steve.
 
T

Tim_Mac

hi Steve,
you're welcome, glad to help out.

you only need to bind the topmost datagrid for the first postback. the
reason for this is because it is a statically declared control in the aspx,
and the viewstate is enough to maintain its state across postbacks.
however, if you change the underlying data, i.e. run an update/delete SQL
query, then you will need to re-bind the datagrid afterwards because the
viewstate data will not reflect your data changes.

the reason your events are getting lost for the secondary datagrid is
because this control does not exist for any given postback unless it is
programatically created exactly as it was previously. does that make sense?

re: events for a DataBind()... i'm not aware of any knock-on events raised
by calling DataBind on a control. if you set a breakpoint at the DataBind
call, and hit F11 you will step into any user code that runs as a result of
calling Databind.

i know what you mean about the complexity of the Page lifecycle. i
generally don't concern myself with such events, except obviously Page_Load.
there is lots of opinion on where/when to create your dynamic controls.
Personally i like to do it all in Page_Load because it is very clear then
what is going on, you don't need to worry about the order of events.
Page_Load will always run first, and then any events will fire after that.
advanced users may say this is too simplistic, but i have done plenty of
complex scenarios containing nested dynamic controls only using Page_Load.

the official resource on the Page/Postback lifecycle is on MSDN2:
http://msdn2.microsoft.com/en-us/library/ms178472.aspx
this really is an excellent article and it is the one i was looking for
earlier but couldn't find. well worth an afternoon of studying. they also
give a few tips for nested databound controls under the heading "catch up
events"

i am stumped by the double Page_Load. i can't see how Page.Postback could
be false unless you have some Response.Redirect code or some javascript to
reload the page, or if your linkbutton doesn't directly cause a postback.
i.e. if it is rendered as <a href="SamePage.aspx?Select=10">Select</a>

can you post the aspx and code-behind? don't worry about the database
connections etc, just by looking at the code it may be clear where the
problem is.

thanks
tim
 
S

Steve Hershoff

Good call on the double page_load, Tim. The "show secondary datagrid" link
does indeed lead to a response.redirect, so that should explain things
there. I'd be glad to post the code-behind info, but I think you've got me
on the right direction.

I'll definitely check out that MSDN2 link you posted on the page lifecycle.
I've had it with guesswork on what gets fired and when!

Indebted as always,

-Steve
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top