我如何拥有ASP.NET模板化复合控件?

时间:2009-03-04 20:19:25

标签: asp.net templates composite-controls

我正在尝试将模板添加到包含Label和TextBox的简化复合控件中。我希望我的标记看起来像这样:

<test:FormItem ID="fi" runat="server" Title="MyTitle" Text="My Text!">
    <TestTemplate>
        <i>
            <%# Container.Title) %></i>
        <br />
        <%# Container.Text %>
    </TestTemplate>
</test:FormItem> 

我有一个templateContainer类,它具有TextBox和Label的属性。

public class TemplateContainer : WebControl, INamingContainer
{

    public TextBox Text { get { return m_item.Text; } }
    public Label Title { get { return m_item.Title; } }

    private FormItem m_item;

    public TemplateContainer(FormItem item)
    {
        m_item = item;
    }

}

在主FormItem类中,我有一个从CreateChildControls()调用的CreateControlHierarchy()方法:

protected virtual void CreateControlHierarchy()
    {

        m_itemTemplateContainer = new TemplateContainer(this);
        TestTemplate.InstantiateIn(m_itemTemplateContainer);

        Controls.Add(m_itemTemplateContainer);

    }

我想要的是模板呈现实际控件。相反,它在控件上调用ToString()并显示System.Web.UI.WebControls.Label和System.Web.UI.WebControls.TextBox。有没有办法让模板将控件添加到它的集合中而不是只调用它们上的ToString()?

注意:我也尝试将文本框和标签添加到容器的控件集合中,它们执行相同的操作。

2 个答案:

答案 0 :(得分:1)

确定。所以我尝试了一些东西,然后我找到了一个好的解决方案。

首先,我尝试在数据绑定表达式中使用方法,然后跟踪容器的Control集合中文本框或标签的位置。但是,CompiledTemplateBuilder(这是.Net内部为标记中指定的ITemplates构建的)将两个绑定表达式之前和之后的所有标记放入一个DataBoundLiteral控件中,并且在调用该方法时已经构建了Control集合。

创建一个新的WebControl是什么工作,它作为复合控件中控件的占位符。它有一个属性Control,当设置时,它将控件添加到它的Controls Collection。

public class FormItemPlaceHolder : WebControl, INamingContainer
{
    public WebControl Control
    {
        get
        {
            if(Controls.Count == 0)
                return null;
            return Controls[0] as WebControl;
        }
        set
        {
            if (Controls.Count != 0)
                Controls.Clear();
            Controls.Add(value);
        }
    }

}

然后在标记中,我创建了一个这种类型的控件,并将它的Control属性绑定到容器中的正确属性。

<test:FormItem ID="fi" runat="server" Title="MyTitle" Text="My Text!">
    <TestTemplate>
        <i>
        <test:FormItemPlaceHolder ID="ph" runat="server" 
            Control='<%# Container.Title %>' />
        </i>
        <br />
         <test:FormItemPlaceHolder ID="ph2" runat="server" 
             Control='<%# Container.Text %>' />
    </TestTemplate>
</test:FormItem>

有没有人有更好的解决方案?

答案 1 :(得分:0)

容器不应该定义控件,只能定义数据。

在标记中,您应该定义数据的实际控件,并从容器中为它们分配值。

E.g。

public class TemplateContainer : UserControl
{
    public string Text { get { return m_text; } }
    public string Title { get { return m_title; } }

    private string m_text;
    private string m_title;
    private FormItem m_item;

    public TemplateContainer(FormItem item)
    {
        m_item = item;
    }

}

在标记中:

   <test:FormItem ID="fi" runat="server" Title="MyTitle" Text="My Text!">
        <TestTemplate>
            <i><asp:Label runat="server" Text='<%# Container.Title) %>' /></i>
            <br />
            <asp:TextBox runat="server" Text='<%# Container.Text %>' />
    </TestTemplate>
</test:FormItem>

如果您尝试创建一个不需要在标记中添加控件的复合控件,那么为什么要使用模板?如果只是为了样式,那么创建自己的Style对象可能会更有效吗?