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

发布于 2024-07-14 03:38:44 字数 1289 浏览 7 评论 0原文

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

<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() ?

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

I am trying to add a template to a simplified composite control containing a Label and a TextBox. I want my mark up to look something like this:

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

I have a templateContainer class that has properties for the TextBox and 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;
    }

}

In the main FormItem class I have a CreateControlHierarchy() method that is being called from CreateChildControls():

protected virtual void CreateControlHierarchy()
    {

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

        Controls.Add(m_itemTemplateContainer);

    }

What I WANT is for the Template to render the actual control. Instead, it's calling ToString() on the control and displaying System.Web.UI.WebControls.Label and System.Web.UI.WebControls.TextBox. Is there a way to make the template add the controls to it's collection instead of just calling ToString() on them?

Note: I've also tried adding the textbox and label to the controls collection of the container which does the same thing.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

酒中人 2024-07-21 03:38:44

好的。 所以我尝试了一些事情,然后想出了一个好的解决方案。

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

所做的工作是创建一个新的 WebControl,它充当复合控件中控件的占位符。 它有一个属性 Control,设置后,会将控件添加到其控件集合中。

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>

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

Ok. So I tried a few things and I came up with an OK solution.

First, I tried to use methods in the data binding expression and then keep track of where in the container's Control collection the textbox or label would go. However, the CompiledTemplateBuilder (which is what .Net internally builds for ITemplates specified in mark up) put all of the markup before and after both binding expressions into one DataBoundLiteral control and the Control collection was already built when the method was called.

What did work was to create a new WebControl which serves as a place holder for the controls within the composite control. It has one property Control and when set, it add the control to it's 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);
        }
    }

}

Then in the mark up, I create a control of this type and bind it's Control property to the correct property in the container.

<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>

Does anyone have a better solution?

ま柒月 2024-07-21 03:38:44

容器不应定义控件,而应定义数据。

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

例如

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 对象可能会更有效?

The container should not define the controls, just the data.

It is in the markup that you should define the actual controls of the data, and assign them the values in from the container.

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

}

And in the markup:

   <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>

If you are trying to create a composite control that does not require controls to be added in the markup, then why are you using a Template? If it is just for styling then perhaps creating your own Style object may be more effective?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文