【问题标题】:dynamic user controls and viewstate - what am I missing动态用户控件和视图状态 - 我错过了什么
【发布时间】:2014-12-30 16:59:21
【问题描述】:

我想在运行时根据用户选择的 DropDownList 选择动态地将用户控件添加到页面中的 PlaceHolder。像这样的:

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);
}

...这几乎可以工作,但在两次回发后我得到了这个:

加载视图状态失败。正在加载视图状态的控制树必须与在先前请求期间用于保存视图状态的控制树匹配。例如,动态添加控件时,回发期间添加的控件必须与初始请求期间添加的控件的类型和位置相匹配。

...我读到的原因是第二次回发的控件与之前的回发不同。我试图通过为控件提供相同的 ID 和类型来防止这种情况,但没有骰子。两个控件:

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

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

我是否缺少部分拼图来完成这项工作?我读过类似的问题,但建议没有成效。

谢谢

【问题讨论】:

    标签: asp.net user-controls dynamic-usercontrols


    【解决方案1】:

    在初始化事件中,你必须确保控制树与之前回传的控制树匹配;所以如果你移除控件,你需要在init运行之后移除它,也就是加载viewstate的时候。

    此外,可能需要在 PreInit 中完成初始加载,您可以尝试看看这是否也有帮助。

    【讨论】:

    • 我没有明确删除任何控件,但就像上面的 Page_Init 一样,我正在根据所选列表值加载不同的控件。在上面的代码中,只加载了所选项目的 UC,其他的则不加载。这肯定是导致不匹配的视图状态控制树的原因。但我不确定如何解决 - 使用上述作为我们的模型,我应该怎么做才能防止这种情况发生?
    • 是的,这就是导致问题的原因。您必须重新加载以前的状态,然后删除旧控件并添加新控件。从动态的角度来看,您可以存储另一个包含当前状态的 ViewState 变量,在初始化时加载它,然后删除旧的并添加新的以达到正确的状态。或者只是加载你提到的所有内容。
    【解决方案2】:

    另一种有效但与我的问题不同的技术是在运行时添加所有内容控件,但将未选择的内容控件的可见性设置为 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;
    }
    

    ...但这感觉不如只加载所需的控件。

    【讨论】:

    • 我建议这样做,因为动态控制管理在 Web 表单中是一种痛苦;但是,由于页面上的控件数量,您将拥有更大的视图状态负载。
    • Visible = False 也不会对标记呈现任何内容,因此页面大小相同,但会保留 ViewState。
    • 如果不需要,您可以随时禁用用户控件实例或其包含的任何子控件上的 ViewState。
    • 是的,我刚刚修改了上面的内容,还包括ucContent.EnableViewState = false; 用于非所需的用户控件。我想这可行……但似乎很奇怪。这些都不是一种非常干净的动态加载内容的方式,但不确定除了上述任何一种之外还有什么动态用户控件。
    猜你喜欢
    • 2011-01-26
    • 1970-01-01
    • 1970-01-01
    • 2010-12-03
    • 1970-01-01
    • 2020-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多