Question

Warning! This problem is not for the feint of heart. I've spent several days in all trying to troubleshoot it.

I have a Wizard control with about 5 steps, each with several controls ranging from very simple to very complex such as custom jQuery combo boxes based on DropDownLists and TextBoxes. Each step has several of the controls wrapped in a PlaceHolder control.

The Wizard along with all PlaceHolders and their child Controls are nested inside of a View of a MultiView. On the same page I have another View styled like a Form, but not one. This view has corresponding PlaceHolders for each of PlaceHolders within each step of the Wizard.

Depending on the ReferralUrl I call the following function to "Toggle" the view from the Wizard to the form style view by moving all the controls, then setting the active view as follows:

Protected Sub ToggleView() Handles ViewToggle.Click
    If Wizard_mv.ActiveViewIndex = 0 Then
        ViewToggle.Text = "Toggle Wizard View"
        fPH1.Controls.Add(wPH1)
        fPH2.Controls.Add(wPH2)
        fPH3.Controls.Add(wPH3)
        fPH4.Controls.Add(wPH4)
        fPH5.Controls.Add(wPH5)
        Wizard_mv.ActiveViewIndex = 1
    ElseIf Wizard_mv.ActiveViewIndex = 1 Then
        ViewToggle.Text = "Toggle Form View"
        wPH1.Controls.Add(fPH1)
        wPH2.Controls.Add(fPH2)
        wPH3.Controls.Add(fPH3)
        wPH4.Controls.Add(fPH4)
        wPH5.Controls.Add(fPH5)
        Wizard_mv.ActiveViewIndex = 0
    End If
End Sub

Immediately after this, I use another function for pre-filling the controls with values from a record in a database. After allowing the users to make some changes, they may resubmit the updated record to the database. The problem is that this works just fine if I do so from the Wizard but not after toggling. The trace shows that the Control Tree is empty at the time of submitting the updated record, and hence I cannot grab the user-entered/pre-filled values from this view. The pre-filling works great and the "Selected" values are all correct. The problem arises on the PostBack after clicking submit and it loses all the values and controls.

Please do not answer unless you fully understand my problem and are willing to help. I think the problem very well lies within the page lifecycle. Mysteriously, when I submit from my Wizard, on the postback in Page_Init I get my control values loaded, however when I submit from my form view, neither the controls nor their values are loaded. From what I read, this is an issue of persistence. Really hoping there's a relatively easy solution for this.

Here's a sample of my markup in my Wizard (all styling removed for brevity):

<asp:WizardStep ID="WizardStep1" runat="server" Title="Product Info">
    <asp:PlaceHolder ID="wPH1" runat="server" ViewStateMode="Enabled">
        <asp:Table ID="ProductInfoTable" runat="server" Width="100%">
            <asp:TableHeaderRow>
                <asp:TableHeaderCell><h3>Product Line</h3></asp:TableHeaderCell>
                <asp:TableHeaderCell><h3>Publication Type</h3></asp:TableHeaderCell>
                <asp:TableHeaderCell><h3>Request Type</h3></asp:TableHeaderCell>
            </asp:TableHeaderRow>
            <asp:TableRow>
                <asp:TableCell>
                    <div class="ui-widget">
                        <!-- Autocomplete Combobox -->
                        <asp:DropDownList ID="productLine_ddl" runat="server" DataSourceID="productLineSDS" ViewStateMode="Enabled" DataTextField="Product" DataValueField="ID"></asp:DropDownList>
                        <asp:TextBox ID="productLine_cb" runat="server" EnableViewState="True"></asp:TextBox>
                        <button id="productLine_btn" type="button" title="Show All Items"></button>
                    </div>
                </asp:TableCell>
                <asp:TableCell>
                    <asp:DropDownList ID="docType_ddl" runat="server" DataSourceID="docTypeSDS" DataTextField="DocType" DataValueField="ID"></asp:DropDownList>
                </asp:TableCell>
                <asp:TableCell>
                    <asp:DropDownList ID="requestType_ddl" runat="server" DataSourceID="requestTypeSDS" DataTextField="RequestType" DataValueField="ID"></asp:DropDownList>
                </asp:TableCell>
            </asp:TableRow>
            <asp:TableRow>
                <asp:TableCell ColumnSpan="2">
                    <asp:MultiView ID="Attachment_mv" runat="server" ActiveViewIndex="0">
                        <!-- File Upload/Browsing Display -->
                        <asp:View ID="AttachmentUploadView" runat="server">
                            <h3 class="inlineH">Attach File: </h3>
                            <asp:FileUpload ID="AttachmentFile_btn" runat="server" />
                            <asp:Button ID="UploadFile_btn" runat="server" Text="Upload File" />
                        </asp:View>
                        <!-- File Attached Display -->
                        <asp:View ID="FileAttachedView" runat="server">
                            <h3 class="inlineH">Uploaded File: </h3>
                            <asp:Label ID="FileAttachedLabel" runat="server" Text="Label"></asp:Label>
                            <asp:Literal ID="FilesOnServer" runat="server" />
                        </asp:View>
                    </asp:MultiView>
                </asp:TableCell>
            </asp:TableRow>
        </asp:Table>
    </asp:PlaceHolder>
</asp:WizardStep>

My Page Lifecycle Events, as requested (in chronological order for your convenience) :)

Dim referrerPage As String
'Initialize Dynamic controls here. These are controls that need to be prefilled, etc.
Private Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Init
    'DO NOT PREFILL at this stage, as the Controls are not yet rendered and will cause errors.
    '  Use this section for detecting the "referrerPage" and missing "id" parameters when expected, etc.
    If Not IsPostBack Then
        ViewState.Clear()
    End If

    Try
        referrerPage = Right(Request.UrlReferrer.AbsolutePath, Len(Request.UrlReferrer.AbsolutePath) - Request.UrlReferrer.AbsolutePath.LastIndexOf("/"c) - 1)
    Catch ex As Exception
        If Not String.IsNullOrEmpty(Session.Item("referrerPage")) Then
            referrerPage = Session.Item("referrerPage")
        End If
    End Try

    If StrComp(referrerPage, "wizard.aspx") <> 0 And String.IsNullOrEmpty(Session.Item("referrerPage")) Then 'Initialize Session state to remember "referrerPage"
        Session.Add("referrerPage", referrerPage)
    End If
    If StrComp(referrerPage, "formdetails.aspx") = 0 Then
        If String.IsNullOrEmpty(Request.Params("id")) Then
            'This line checks for an expected "id" param value and if none exists, forwards the page back to "tcom.aspx"
            Response.Redirect(Request.UrlReferrer.AbsolutePath)
        Else
            ToggleView()
        End If
    End If
End Sub

'Prefill Dynamic controls here.
Private Sub Page_PreLoad(sender As Object, e As EventArgs) Handles Me.PreLoad
    If Not IsPostBack Then
        productLine_ddl.DataBind()
        docType_ddl.DataBind()
        requestType_ddl.DataBind()
        '...and several more DataBinds for each individual
        '   control in the wizard. Nothing more.
    End If
End Sub

Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
    If Not IsPostBack Then
        'Benign code for querying the database to get User info for Page.User.Identity.Name
    End If
End Sub

Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As EventArgs) Handles Me.PreRender
    If Not IsPostBack Then
        'Here is completely benign code for hiding a couple controls.
    End If
End Sub

Protected Sub Page_PreRenderComplete(ByVal sender As Object, ByVal e As EventArgs) Handles Me.PreRenderComplete
    'PREFILL HERE when appropriate. This occurs after checking the "referrerPage" and ensuring a value for the "id" parameter.
    If Not IsPostBack Then
        Try
            If Not String.IsNullOrEmpty(Request.Params("id")) Then
                PrefillWizard(Request.Params("id"))
            Else : output.Text += "Source: " + Request.UrlReferrer.AbsolutePath
            End If
        Catch ex As Exception
        End Try
    End If
End Sub

To anyone who can help with this, you have my eternal gratitude. ;)

Was it helpful?

Solution

The problem is that the control tree of the page must be exactly the same during every postback. That means that you have to add all the control every time no mater which ActiveViewIndex is set. Preferably in CreateChildControls or page init. In the ToggleView function you can than set the visibility of the controls.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top