从用户控件内添加页面控件集合

时间:2011-02-12 01:57:31

标签: asp.net vb.net user-controls jquery-ui-dialog

我有一个asp.net usercontrol,它代表一个“弹出”对话框。基本上,它是jQuery UI对话框的包装器,它可以被子类化以轻松地进行对话。

作为此控件的一部分,我需要在控件所使用的页面中注入一个div,在窗体的最顶部或最底部,以便在弹出实例化时,将其父级更改为此div 。这允许“嵌套”弹出窗口,而不会将子弹出窗口嵌入父窗口中。

麻烦的是,我找不到一种安全的方法将这个div注入页面。 usercontrol没有preinit事件,所以我不能在那里执行,并且在Init,Load或PreRender中调用Page.Form.Controls.Add(...)会导致标准异常“控件集合无法修改在DataBind,Init,Load,PreRender或Unload阶段。“

我以为我找到了一个使用...

的解决方案
ScriptManager.RegisterClientScriptBlock(Page, Me.GetType, UniqueID + "_Dialog_Div", containerDiv, False)

...它似乎正常工作,但最近一位同事尝试在对话框中放置一个UpdatePanel,现在她收到错误“脚本标签注册类型'ASP.controls_order_viewzips_ascx'和键'ctl00 $ ContentBody $ OViewZips_Dialog_Div '脚本标记之外的字符无效:。只能注册格式正确的脚本标记。“

你应该如何从用户控件中向页面控件集合添加控件?

2 个答案:

答案 0 :(得分:7)

我不确定为什么你真的需要将这个div添加到页面的表单中,但这应该有效:

  Public Class WebUserControl1
    Inherits System.Web.UI.UserControl

        Private Sub UC_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
            AddHandler Me.Page.Init, AddressOf Me.Page_Init
        End Sub

        Private Sub Page_Init(ByVal sender As Object, ByVal e As EventArgs)
            Dim dialogDiv As New Panel
            dialogDiv.ID = "DialogDiv"
            If Not Page.Form.Controls.Contains(dialogDiv) Then
                Page.Form.Controls.AddAt(0, dialogDiv)
            End If
        End Sub

    End Class

  

如何在C#中实现它。我总是得到错误控件   无法在Load,PreRender上修改集合       我需要一个Literal Control从用户控件添加到我的母版页头。文字控件将包含css链接。

是否要将文字添加到主文件中的HeadContent - ContentPlaceHolder控件或页面的标题(html头元素)中?但是,我在这里展示了两者。

以下是UserControl的代码隐藏:

public partial class UC_AddToMaster : System.Web.UI.UserControl
{
    private void Page_Init(object sender, System.EventArgs e)
    {
        this.Page.Init += UC_AddToMaster_Init;
    }

    private void UC_AddToMaster_Init(object sender, EventArgs e)
    {
        Literal literal = new Literal{ Text = "Hi World!" };
        // if you want to add it to the header of the page:
        if (!Page.Header.Controls.Contains(literal))
        {
            Page.Header.Controls.AddAt(0, literal);
        }

        // if you want to add it to the master's HeadContent ContentPlaceHolder control:
        var siteMaster = Page.Master as SiteMaster;
        if (siteMaster != null)
        {
            if (!siteMaster.Head.Controls.Contains(literal))
            {
                siteMaster.Head.Controls.AddAt(0, literal);
            }
        }
    }
}

对于上面提到的HeadContent方法,我在主人中提供了以下属性:

// in the master
public ContentPlaceHolder Head { get { return this.HeadContent; } }

因此我需要在SiteMaster中将页面的主要内容强制转换为它的实际类型(UserControl)。否则我无法访问此属性。

答案 1 :(得分:4)

Usercontrol没有PreInit事件,但没有任何东西阻止您向UserControl中的Page PreInit事件添加处理程序:

Page.PreInit += new EventHandler(Page_PreInit);

编辑 - 你是对的 - 你无法从用户控件捕获PreInit,虽然我很惊讶你不能 - 但你仍然可以通过向UserControl的构造函数添加代码来更改页面控件集合。我试过这个并且有效。

public MyUsercontrol()
{
    Page page = (Page)HttpContext.Current.Handler;
    Literal lit = new Literal();
    lit.Text="text";
    page.Controls.Add(lit);
}

在构造函数编译中向Page.PreInit添加一个事件处理程序,但它永远不会触发。

(结束编辑)

那就是说,我不确定为什么这对实现你的目标是必要的。你为什么不让你的对话框控件在你将它放入表单的任何地方呈现它自己的div,并将其用作父类,而不是尝试在表单中的其他地方创建一个?我无法想到为什么在表格的开头或结尾处进行物理渲染会很重要。这是一个对话框,所以在你使用它之前它总是不可见的,对吗?