This problem has got me scratching my head.

I have an ASP .NET wizard control. Within the step view, I put a user control. The user control contains a FormView. The Formview contains a mixture of standard ASP .NET controls and other user controls.

In one situation, I have two user controls containing a dropdown list control. I set up an event to fire if the selectedindex of the first dropdown list control changes (which is set to AutoPostback), and the wizard control subscribes to this event. In the event handler of the wizard control, if the first dropdown has a certain value, I want to disable the dropdown in the second user control. So I set up something like this:

private void MyEventHandler(object sender, myeventargs e)
{
//get the formview
FormView _fv = (FormView) this.MainUserControl.FindControl("FormView1");
//get the usercontrol containing the dropdown I want to disable 
SecondUserControl _sc = (SecondUserControl) _fv.FindControl("FormViewInsertTemplate_SecondUserControl");
//get the dropdown I want to disable from the second user control
DropDownList _ddl = (DropDownList) _sc.FindControl("SecondDropDown");
//if the dropdownlist in the first user control has the value I want, disable the second dropdown
if (e.SelectedValue == "The Value I Want")
{_ddl.Enabled = false;} 
}

Here's the problem. I can't disable the second dropdown. The second dropdown remains enabled.

Now, if I try to disable the second dropdown when the NextButtonClick event fires when moving from the previous wizard stop, using similar code as above, I have no problem. Using FindControl, I can get the dropdown I need to disable it. But when I do this after the controls have been rendered in the step, I can't disable the dropdown on a postback, I can't set it as invisible, I can't change the background color, etc. I don't know why this is the case.

I've tried a number of things to get this to work including:

  1. Create a property in the usercontrol that contains the dropdown and trying to disable the dropdown from within the usercontrol by setting the property in the wizard control ( this.usercontrol.enabledropdownproperty = false; )
  2. Rebinding the dropdown
  3. Trying to save the state of the wizard control after trying to disable the dropdown using both SaveViewState and SaveControlState (my thought being that dropdown wasn't being disabled because it was being retrieved from the viewstate saved prior to the postback)
  4. Trying to disable both the dropdown and usercontrol (that didn't work either)
  5. Setting the enable viewstate property for the dropdown, usercontrol, and formview to false, hoping the wizard control viewstate will take care of the child control viewstates

As an experiment, I added a dropdown to the view of another wizard step, setting it to autopostback, and in the selectedindex change event disabling the dropdown. This works! So in my situation, either I'm not getting the correct dropdown to disable, or the fact that it is embedded in a user control is not allowing changes once the control is rendered, or the control is being reinitialized (which I don't think it is because the first dropdown retains the "The Value I Want" value I selected instead of a default value).

Can someone explain why I can disable a dropdown in a usercontrol when moving from a previous wizard step, but I can't disable the dropdown in the postback of the step where I need to disable it, yet I can disable a dropdown in a step postback if the dropdown is an immediate child control of the wizard control (that is to say, not part of a usercontrol, formview, etc.)?

I tried something else.

I added a new dropdown to the wizard control step, outside of any existing user control in the wizard view (so this dropdown is an immediate child control of the wizard control, not embedded in a user control ), put in two items ("yes", "no"), and set autopostback to true.

First, I tried to disable this new dropdown at the same place I'm trying to disable the other dropdowns; in the event I set up in my example (this event is fired when the selectedindex changes for a dropdown in another usercontrol). I couldn't disable my test dropdown.

Then I set up a selected index change event handler for this new dropdown in the wizard control code behind and tried to disable the dropdown there. This worked!!

So maybe my problem has nothing to do with where the dropdownlist control is located (standalone or within a user control), and everything to do with where I'm trying to disable the controls. Just a guess, but maybe the wizard control isn't doing a postback in the event I created. When the first dropdown (the one I need to look at for the value) does it's selectedindexchange postback, it posts back to the user control that contains it, then fires off the event I created that then gets handled in the wizard control. Even though I'm handling the event, and even though I can step through the event's code behind, maybe the wizard control isn't doing a postback when handling the event I created. When I make the change capture the selectedindexchanged event for the new dropdown, the wizard control does do a postback based on the dropdown's autopostback property.

Anyone have any ideas about this, and ideas how I can get this to work?

Oh, I forgot to mention that I put a breakpoint in wizard control Page_Load and examined Page.IsPostBack. When the wizard control handles the event I set up, Page.IsPostBack is true.

Two more clues:

I looked at two dropdownlist properties while debugging.

  1. For DropDownList1, I'm attempting to disable it in the event I set up that responds to another dropdown's selected index changing. This disable, as I mentioned previously, does not work.
  2. For DropDownList2, I'm attempting to disable it in an event I set up in the wizard control for selectedindexchanging (the dropdown is set to autopostback). This dropdownlist is not embedded in any user control and is an immediate child of the wizard control. As mentioned previously, I am able to disable this dropdownlist.

What I found is:

  1. DropDownList1 has two properties that are set to false: _pagePreLoadFired and _stateLoaded
  2. DropDownList2 has the same two properties set to true

I'm finding very little information about these two non-public fields other then some information about setting _pagePreLoadFired an accordion Ajax control and some databinding requirements in OnPagePreLoad.

Can anyone tell me if and why this is significant, if it could be a clue to the problems I'm having, and a suggested workaround?

Now I have even more clues.

I enabled trace and put out a Trace.Warn message before and after I try to disable the dropdownlists that I haven't been able to disable (dropdownlist is part of a user control, an event handler is set up in wizard control that gets fired when the dropdown's selectedindex event is handled in the user control). Here is the trace information (I've edited out the time information):

aspx.page Begin PreInit   
aspx.page End PreInit 
aspx.page Begin Init 
aspx.page End Init 
aspx.page Begin InitComplete 
aspx.page End InitComplete 
aspx.page Begin LoadState 
aspx.page End LoadState 
aspx.page Begin ProcessPostData 
aspx.page End ProcessPostData
aspx.page Begin PreLoad 
aspx.page End PreLoad 
aspx.page Begin Load 
debugging Begin Page Load 
aspx.page End Load 
aspx.page Begin ProcessPostData Second Try 
aspx.page End ProcessPostData Second Try 
aspx.page Begin Raise ChangedEvents 
aspx.page End Raise ChangedEvents 
aspx.page Begin Raise PostBackEvent 
aspx.page End Raise PostBackEvent 
aspx.page Begin LoadComplete 
aspx.page End LoadComplete 
aspx.page Begin PreRender 
aspx.page End PreRender 
aspx.page Begin PreRenderComplete 
aspx.page End PreRenderComplete
aspx.page Begin SaveState 
aspx.page End SaveState 
aspx.page Begin SaveStateComplete 
aspx.page End SaveStateComplete 
aspx.page Begin Render 
aspx.page End Render

All that is available is a Trace.Warn message I put in Page Load.

Now here is the trace information for the other dropdownlist scenario I have (autopostback, not part of a user control, selectedindexchanged event handled in the wizard control).

aspx.page Begin PreInit   
aspx.page End PreInit 
aspx.page Begin Init
aspx.page End Init 
aspx.page Begin InitComplete 
aspx.page End InitComplete 
aspx.page Begin LoadState 
aspx.page End LoadState 
aspx.page Begin ProcessPostData 
aspx.page End ProcessPostData
aspx.page Begin PreLoad 
aspx.page End PreLoad 
aspx.page Begin Load 
debugging Begin Page Load 
aspx.page End Load 
aspx.page Begin ProcessPostData Second Try 
aspx.page End ProcessPostData Second Try 
aspx.page Begin Raise ChangedEvents 
debugging Begin DropDownList1 Disable 
debugging End DropDownList1 Disable 
aspx.page End Raise ChangedEvents 
aspx.page Begin Raise PostBackEvent 
aspx.page End Raise PostBackEvent 
aspx.page Begin LoadComplete 
aspx.page End LoadComplete 
aspx.page Begin PreRender  
aspx.page End PreRender 
aspx.page Begin PreRenderComplete 
aspx.page End PreRenderComplete 
aspx.page Begin SaveState 
aspx.page End SaveState 
aspx.page Begin SaveStateComplete 
aspx.page End SaveStateComplete 
aspx.page Begin Render 
aspx.page End Render

So it looks like I haven't been able to disable some dropdownlists because everything has already been loaded and rendered. It seems that the event handler I created gets processed too late in the page cycle to make any control changes in code.

Does anyone know how I can correct this?

Now I have even more clues.

I was mistaken when I said that my dropdownlist disable wasn't working in my event handler because "everything has already been loaded and rendered". What was really happening was that my Trace.Warn message in that event handler wasn't being written to the log. I'm not sure why, but I looked at a trace private variable called Trace._endDataCollected and it was true. At other points in the application (points where Trace.Warn messages were being written to the log), it was false. Very strange. I'm not sure at what point trace information collection ended.

I was also able to determine that my event handler fired before the RaisePostBackEvent event, but I'm not sure if it fired before the end of RaisePostDataChangedEvent.

I spent some time reading this article on page life cycle (http://www.15seconds.com/issue/020102.htm) and looked through the example code to figure out a workaround! Instead of depending on an event handler fired by a selected index change in a user control, I put something like this in the OnLoad method:

protected override void OnLoad(EventArgs e)
            {
            base.OnLoad(e);
            if (Wizard1.ActiveStep.Name == "The step I want")
            {
            //get the formview
            FormView _fv = (FormView) this.MainUserControl.FindControl("FormView1");
            //get the first user control containing the dropdownlist I want to examine
            FirstUserControl _fc = (FirstUserControl) _fv.FindControl("FormViewInsertTemplate_FirstUserControl");
            //get the second usercontrol containing the dropdown I want to disable
            SecondUserControl _sc = (SecondUserControl)_fv.FindControl("FormViewInsertTemplate_SecondUserControl");
            //get the first dropdown I want to examine from the first user control
            DropDownList _ddlfirst = (DropDownList) _fc.FindControl("FirstDropDown");                    
            //get the dropdown I want to disable from the second user control
            DropDownList _ddl = (DropDownList) _sc.FindControl("SecondDropDown");
            if (_ddlFirst.SelectedValue == "The Value I Want")
            {
             _ddlSecond.Enabled = false;        
            }
            else
            {
             _ddlSecond.Enabled = true;
             }
           }
        }

Doing things this way disables the dropdownlist that I need to disable!

I'm still not sure why trying to disable the dropdownlist control in the event handler didn't work, nor am I sure why Trace._endDataCollected was set to true by the time processing got to the event handler, but at least I got something to work.

I'd still like to know exactly where in the page life cycle the event handler is fired but, since I couldn't do an override of RaisePostDataChangedEvent, I can only guess. If anyone has any ideas on how I can debug this further, please let me know.

The plot gets thicker.

I put a Trace.Warn message in my first user control (which has a dropdownlist set to autopostback) in the selectedindexchanged event handler of the dropdownlist.

aspx.page Begin PreInit   
aspx.page End PreInit 
aspx.page Begin Init
aspx.page End Init
aspx.page Begin InitComplete 
aspx.page End InitComplete
aspx.page Begin LoadState 
aspx.page End LoadState 
aspx.page Begin ProcessPostData 
aspx.page End ProcessPostData 
aspx.page Begin PreLoad 
aspx.page End PreLoad 
aspx.page Begin Load 
 In OnLoad 
aspx.page End Load 
aspx.page Begin ProcessPostData Second Try 
aspx.page End ProcessPostData Second Try 
aspx.page Begin Raise ChangedEvents 
 In first user control selected index change event handler 
aspx.page End Raise ChangedEvents 
aspx.page Begin Raise PostBackEvent 
aspx.page End Raise PostBackEvent 
aspx.page Begin LoadComplete 
aspx.page End LoadComplete 
aspx.page Begin PreRender 
aspx.page End PreRender 
aspx.page Begin PreRenderComplete 
aspx.page End PreRenderComplete 
aspx.page Begin SaveState 
aspx.page End SaveState  
aspx.page Begin SaveStateComplete 
aspx.page End SaveStateComplete 
aspx.page Begin Render 
aspx.page End Render

It looks like the first dropdownlist selectedindexchanged event is happening within the RaiseChangedEvents. I fire off an event at this point, which gets handled in the wizard control, at which point I try to disable a second dropdownlist. As mentioned previously, I can't disable the second dropdownlist here, a Trace.Warn message in this event doesn't write to the log, etc.

My guess is that the wizard control only sees the first dropdownlist autopostback as a "changed" event. By the time I try to disable the second dropdownlist in the event handler in the wizard control, the page life cycle has already loaded viewstate to the second dropdownlist and doesn't recognize the code behind disable control as a change. As mentioned in the article I linked to "each control is flagged with a Boolean on whether its data was actually changed or remains the same since the previous submit." The first dropdownlist is flagged but when trying to disable the second dropdownlist in the event handler in the wizard control, it is too late in the page life cycle for it to be flagged as a change.

This is only a guess, of course, and doesn't explain why, if two dropdownlist controls are immediate child controls of the wizard control, you can put in a selectedindexchanged event for one dropdownlist and still be able to disable a second dropdownlist. After all, the "changed" control is the first dropdownlist, and disabling the second dropdownlist control should happen at the same point in the page life cycle.

I'm still baffled by this.

I'm still not able to figure out this problem. Maybe a "picture" will be worth a thousand words. I've attached a zip file that contains a sample program that functions similarly to the application I'm having problems with.

Default.aspx.cs contains two methods: Page_Load and an event handler. Page_Load contains the event subscription for Dropdown1 change index. It also contains commented out code that looks at the selected value of Dropdown1 and disables Dropdown2 if the value is "Yes." This block of code works when uncommented. Dropdown 2 is disabled.

The event handler also attempts to disable Dropdown2. If the event argument (the selected value of Dropdown1) is "Yes," Dropdown2 is disabled. Only it isn't. And that's the problem. I can't figure out why I can't disable the second dropdown here. If I try to do something like change the background color of Dropdown2, that also doesn't work. And, as I mentioned before, if I put a Trace.Warn message in this method, it doesn't get written to the trace log. You can step through the code in debugger but some things don't seem to work.

The rest of the code is various user controls and event classes.

Let me know if you find something I haven't found.

have you looked at the page pre-render event, you may be running into an order/timing issue

This article has been dead for over six months. Start a new discussion instead.