【问题标题】:How can I have an ASP.NET templated composite control?如何拥有 ASP.NET 模板化复合控件?
【发布时间】:2009-03-11 08:09:23
【问题描述】:

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

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

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

【问题讨论】:

    标签: asp.net templates composite-controls


    【解决方案1】:

    好的。所以我尝试了一些方法,我想出了一个好的解决方案。

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

    起作用的是创建一个新的 WebControl,它充当复合控件中控件的占位符。它有一个属性 Control,当设置时,它将控件添加到它的 Controls 集合中。

    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>
    

    谁有更好的解决方案?

    【讨论】:

      【解决方案2】:

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

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

      例如

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

      【讨论】:

      • 我想创建一个复合控件(控件的控件)并允许用户在控件周围添加标记。注意:我不想创建 UserControl。我对复合控件中的控件有自定义逻辑,我希望它可以跨应用程序使用。
      • 您的用户是否必须能够自己移动实际控件,或者只是能够在它们之前和之后放置标记?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-05-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-02-23
      • 1970-01-01
      相关资源
      最近更新 更多