0
votes

I'd like to add usercontrols to a PlaceHolder in my page dynamically at run-time, based on which DropDownList selection a user has chosen. Something like this:

protected void Page_Init(object sender, EventArgs e)
{
    //get user's content selection
    int contentMode;

    if (!IsPostBack)
        contentMode = 1;
    else
        contentMode = Int32.Parse(Request.Form[ddlMode.UniqueID]);

    //load a user control
    ContentControl ucContent = null;

    switch (contentMode)
    {
        case 1:
            ucContent = LoadControl("~/Controls/SomeContent1.ascx") as ContentControl;
            break;
        case 2:
            ucContent = LoadControl("~/Controls/SomeContent2.ascx") as ContentControl;
            break;
    }

    ucContent.ID = "ucContent"; 

    phContentArea.Controls.Add(ucContent);
}

...this almost works, but after two postbacks I get this:

Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate during the previous request. For example, when adding controls dynamically, the controls added during a post-back must match the type and position of the controls added during the initial request.

...which I've read is owing to the controls being different on the second postback than they were the prior postback. I've tried to prevent this by giving the control the same ID and type, but no dice. The two controls:

public partial class SomeContent1 : Foo.Bases.ContentControl
{
    //code
}

public partial class SomeContent2 : Foo.Bases.ContentControl
{
    //code
}

Is there a part of the puzzle I'm missing to make this work? I've read similar questions but the suggestions weren't fruitful.

thanks

2

2 Answers

0
votes

In the init event, you have to make sure the control tree matches the previous control tree posted back; so if you remove controls, you need to remove it after init runs, which is when viewstate is loaded.

Also, initial loading may need to be done in PreInit, which you could try to see if that also helps.

0
votes

a different technique that works, but is different than the one in my question, is to add all the content controls at run-time, but set the visibility of the non-selected ones to False:

switch (contentMode)
{
    case 1:
        ucContent = LoadControl("~/Controls/SomeContent1.ascx") as ContentControl;
        phContentArea.Controls.Add(ucContent);

        ucContent = LoadControl("~/Controls/SomeContent2.ascx") as ContentControl;
        ucContent.Visible = false;
        ucContent.EnableViewState = false;
        phContentArea.Controls.Add(ucContent);    
        break;

    case 2:
        ucContent = LoadControl("~/Controls/SomeContent1.ascx") as ContentControl;
        ucContent.Visible = false;
        ucContent.EnableViewState = false;
        phContentArea.Controls.Add(ucContent);

        ucContent = LoadControl("~/Controls/SomeContent2.ascx") as ContentControl;
        phContentArea.Controls.Add(ucContent);
        break;
}

...but this doesn't feel as good as loading only the desired control.