在ASP.NET自定义控件中呈现多个控件集合

时间:2022-09-02 13:34:05

I've build a custom WebControl, which has the following structure:

我已经构建了一个自定义WebControl,它具有以下结构:

<gws:ModalBox ID="ModalBox1" HeaderText="Title" runat="server">
    <Contents>
        <asp:Label ID="KeywordLabel" AssociatedControlID="KeywordTextBox" runat="server">Keyword: </asp:Label><br />
        <asp:TextBox ID="KeywordTextBox" Text="" runat="server" />
    </Contents>
    <Footer>(controls...)</Footer>
</gws:ModalBox>

The control contains two ControlCollection properties, 'Contents' and 'Footer'. Never tried to build a control with multiple control collections, but solved it like this (simplified):

该控件包含两个ControlCollection属性,'Contents'和'Footer'。从未尝试构建具有多个控件集合的控件,但是像这样(简化)解决了它:

[PersistChildren(false), ParseChildren(true)]
public class ModalBox : WebControl
{
    private ControlCollection _contents;
    private ControlCollection _footer;

    public ModalBox()
        : base()
    {
        this._contents = base.CreateControlCollection();
        this._footer = base.CreateControlCollection();
    }

    [PersistenceMode(PersistenceMode.InnerProperty)]
    public ControlCollection Contents { get { return this._contents; } }

    [PersistenceMode(PersistenceMode.InnerProperty)]
    public ControlCollection Footer { get { return this._footer; } }

    protected override void RenderContents(HtmlTextWriter output)
    {
        // Render content controls.
        foreach (Control control in this.Contents)
        {
            control.RenderControl(output);
        }

        // Render footer controls.
        foreach (Control control in this.Footer)
        {
            control.RenderControl(output);
        }
    }
}

However it seems to render properly, it doesn't work anymore if I add some asp.net labels and input controls inside the property (see above asp.net code). I'll get the HttpException:

但是它似乎正确呈现,如果我在属性中添加一些asp.net标签和输入控件,它就不再起作用了(参见上面的asp.net代码)。我会得到HttpException:

Unable to find control with id 'KeywordTextBox' that is associated with the Label 'KeywordLabel'.

无法找到与标识'KeywordLabel'关联的id'KeywordTextBox'的控件。

Somewhat understandable, because the label appears before the textbox in the controlcollection. However, with default asp.net controls it does work, so why doesn't this work? What am I doing wrong? Is it even possible to have two control collections in one control? Should I render it differently?

有点可以理解,因为标签出现在controlcollection中的文本框之前。但是,使用默认的asp.net控件确实可行,所以为什么这不起作用呢?我究竟做错了什么?甚至可以在一个控件中有两个控件集合吗?我应该以不同的方式呈现它

Thanks for replies.

谢谢你的回复。

2 个解决方案

#1


2  

You can use two Panels as parents of your two control collections (and they would provide grouping and improved readability). Add your controls from each collection to the Controls collection of respective panel, and in the Render method just call Render methods of each panel. Panels will automatically render their children, and will provide them with their own namespace, so, you can have controls with similar IDs in different panels.

您可以使用两个Panel作为两个控件集合的父级(它们将提供分组和提高的可读性)。将每个集合中的控件添加到相应面板的Controls集合中,并在Render方法中调用每个面板的Render方法。面板将自动呈现其子项,并为它们提供自己的命名空间,因此,您可以在不同的面板中具有类似ID的控件。

#2


1  

I'm not sure that will work. If you make use of templates however you can get the control to render output correctly.

我不确定它会起作用。如果使用模板,则可以使控件正确呈现输出。

First, define a class to be used as the type for the container control:

首先,定义一个类作为容器控件的类型:

public class ContentsTemplate : Control, INamingContainer
{
}

And now the custom control:

现在自定义控件:

[PersistChildren(false), ParseChildren(true)]
public class ModalBox : CompositeControl
{

  [PersistenceMode(PersistenceMode.InnerProperty)]
  [TemplateContainer(typeof(ContentsTemplate))]
  public ITemplate Contents { get; set; }

  [PersistenceMode(PersistenceMode.InnerProperty)]
  [TemplateContainer(typeof(ContentsTemplate))]
  public ITemplate Footer { get; set; }

  protected override void CreateChildControls()
  {
    Controls.Clear();

    var contentsItem = new ContentsTemplate();
    Contents.InstantiateIn(contentsItem);
    Controls.Add(contentsItem);

    var footerItem = new ContentsTemplate();
    Footer.InstantiateIn(footerItem);
    Controls.Add(footerItem);
  }

}

#1


2  

You can use two Panels as parents of your two control collections (and they would provide grouping and improved readability). Add your controls from each collection to the Controls collection of respective panel, and in the Render method just call Render methods of each panel. Panels will automatically render their children, and will provide them with their own namespace, so, you can have controls with similar IDs in different panels.

您可以使用两个Panel作为两个控件集合的父级(它们将提供分组和提高的可读性)。将每个集合中的控件添加到相应面板的Controls集合中,并在Render方法中调用每个面板的Render方法。面板将自动呈现其子项,并为它们提供自己的命名空间,因此,您可以在不同的面板中具有类似ID的控件。

#2


1  

I'm not sure that will work. If you make use of templates however you can get the control to render output correctly.

我不确定它会起作用。如果使用模板,则可以使控件正确呈现输出。

First, define a class to be used as the type for the container control:

首先,定义一个类作为容器控件的类型:

public class ContentsTemplate : Control, INamingContainer
{
}

And now the custom control:

现在自定义控件:

[PersistChildren(false), ParseChildren(true)]
public class ModalBox : CompositeControl
{

  [PersistenceMode(PersistenceMode.InnerProperty)]
  [TemplateContainer(typeof(ContentsTemplate))]
  public ITemplate Contents { get; set; }

  [PersistenceMode(PersistenceMode.InnerProperty)]
  [TemplateContainer(typeof(ContentsTemplate))]
  public ITemplate Footer { get; set; }

  protected override void CreateChildControls()
  {
    Controls.Clear();

    var contentsItem = new ContentsTemplate();
    Contents.InstantiateIn(contentsItem);
    Controls.Add(contentsItem);

    var footerItem = new ContentsTemplate();
    Footer.InstantiateIn(footerItem);
    Controls.Add(footerItem);
  }

}