ASP.NET 服务器控件内联模板

本文详细介绍了ASP.NET中的模板控件概念,包括模板化控件如何实现内容与外观分离,以及如何创建模板用户控件。讨论了ParseChildrenAttribute的作用,解释了如何通过内联模板语法来定义服务器控件的内容和样式。此外,还提供了创建模板化ASP.NET用户控件的步骤,强调了模板容器、ITemplate接口和CreateChildControls方法的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.模板控件概念

模板控件概念:

模板控件可以使内容与外观分离。典型的应用有Repeater、DataList。

ASP.NET 提供了一种称为模板的通用功能,允许将控制数据与其表示分开。模板化控件本身不提供用户界面 (UI)。该控件的 UI 由页面开发人员通过内联模板提供,该模板允许页面开发人员自定义该控件的 UI。

 

开发模板化控件的方法:

  1. 实现 System.Web.UI.INamingContainer 接口。这是没有任何方法的标记接口。它可以在您的控件下创建新的命名范围,这样子控件就在名称树中有了唯一的标识符。
    [C#]
    public class TemplatedFirstControl : Control,INamingContainer {...}
  2. 将 ParseChildrenAttribute 应用到您的控件,并传递 true 作为参数。在 ASP.NET 页上声明性地使用控件时,这样可指示页分析器如何分析模板属性标记。步骤 3 说明如何定义一个模板属性。
    注意   如果您的控件是从 WebControl 派生的,则不需要应用 ParseChildrenAttribute,因为 WebControl 已经用该属性作了标记。
    [C#]
    [ ParseChildren(ChildrenAsProperties = true)]
    public class TemplatedFirstControl : Control, INamingContainer {...}
    有关 ParseChildrenAttribute 的更多信息,请参见使用 ParseChildrenAttribute。
  3. 定义 System.Web.UI.ITemplate 类型的一个或多个属性。ITemplate 有一个方法 InstantiateIn,该方法可使用页上内联提供的模板创建控件。您不必实现 InstantiateIn 方法;ASP.NET 页框架可提供这种实现。ITemplate 属性必须有 System.Web.UI.TemplateContainerAttribute 类型的元数据属性,它指出哪种 INamingContainer 控件将拥有实例化模板。这在步骤 4 中作了说明。以下代码片段定义了一个模板属性。
    [C#]
    [TemplateContainer(typeof(FirstTemplateContainer))] public ITemplate FirstTemplate {...}
  4. TemplateContainerAttribute 的参数是您想在其中实例化模板的容器控件类型。容器控件独立于正在创作的模板化控件。具有逻辑容器的原因是:模板化控件通常有一个模板,该模板需要使用不同数据重复实例化。拥有与根模板化控件不同的容器控件,使拥有多个此类示例成为可能。逻辑容器是该模板内子控件的即时 INamingContainer。在开发模板化数据绑定控件中更详细地介绍了这种关系。
    注意   容器控件本身必须实现 INamingContainer,因为它有需要在页上唯一命名的子控件。
    [C#]
    public class FirstTemplateContainer : Control, INamingContainer {...}
  5. 重写 CreateChildControls 方法以便在模板中创建子控件。这是通过三个步骤来完成的。
    1. 实例化模板容器。
    2. 调用模板属性的 InstantiateIn 方法并将该容器作为参数传递给它。InstantiateIn 方法(在 ITemplate 接口中声明)实例化该模板的元素,作为该模板容器的子控件。您不必实现 InstantiateIn 方法;ASP.NET 页框架可提供这种实现。
    3. 将模板容器的示例添加到您的模板化控件的 Controls 集合。
      以下代码片段说明了 CreateChildControls 的实现。
      [C#]
      private Control myTemplateContainer;
      protected override void CreateChildControls () {
      if (FirstTemplate != null)
      {
      myTemplateContainer = new FirstTemplateContainer(this);
      FirstTemplate.InstantiateIn(myTemplateContainer);
      Controls.Add(myTemplateContainer);
      }
      else
      {
      Controls.Add(new LiteralControl(Text + " " + DateTime));
      }
      }
  6. 重写从 Control 继承的 OnDataBinding 方法以调用 EnsureChildControls 方法。这样可保证在页框架尝试计算模板内任何数据绑定表达式之前,创建模板中的子控件。您还必须调用基类的 OnDataBinding 方法以确保调用已注册的事件处理程序。
    [C#]
    protected override void OnDataBinding(EventArgs e) {
    EnsureChildControls();
    base.OnDataBinding(e);
    }
  7. 在步骤 5 中,在 CreateChildControls 方法内重复该逻辑,以便为控件的每个模板属性实例化一个模板。

 

相关知识:

 

有关ParseChildrenAttribute的概念:

ParseChildrenAttribute 是在类级别应用的 .NET Framework 元数据属性。它使控件能够指定当在 ASP.NET 页上以声明方式使用该控件时,页分析器如何解释在控件标记内嵌套的元素。可以使用与布尔标志对应的命名参数和该控件的默认属性创建 ParseChildrenAttribute。有关该属性语法的详细信息,请参见 System.Web.UI.ParseChildrenAttribute。

 

以下示例说明如何将 ParseChildrenAttribute 应用于一个控件。

 

[C#]

[ ParseChildren(ChildrenAsProperties = true)]

// Or apply as [ ParseChildren(true)].

public class TemplatedFirstControl : Control, INamingContainer {...}

 

[Visual Basic]

<ParseChildren(ChildrenAsProperties := True)> _

Public Class TemplatedFirstControl

   Inherits Control

   Implements INamingContainer

   ...

End Class

 

有关用 ParseChildrenAttribute 标记的控件的示例,请参见模板化控件示例。当在一页上以声明方式使用 TemplatedFirstControl 时,其控件标记内的子元素(直接子元素)必须对应于 TemplatedFirstControl 的属性,如以下示例中所示。

 

<%-- FirstTemplate is a property of TemplatedFirstControl. --%>

<%-- Custom is the tag prefix for TemplatedFirstControl on the page as defined in the <%@ Register %> directive. --%>

<Custom:TemplatedFirstControl id = "First" Text= "The time on the server is " runat=server>                        

   <FirstTemplate>

       <h3><font face="Verdana" color = "red"><%# Container.Text %> <%# Container.DateTime %>

       </font></h3>

    </FirstTemplate>     

</Custom:TemplatedFirstControl>

 

下表描述 ParseChildrenAttribute 的使用模式。

 

属性用法 说明

ParseChildrenAttribute(ChildrenAsProperties = true)

 

ParseChildren(true)

 嵌套的(子)元素必须对应于控件的属性。控件标记间的其他(非属性)元素和文本生成分析器错误。

示例:Repeater 和其他数据绑定控件。

 

ParseChildrenAttribute(ChildrenAsProperties = false)

 

ParseChildrenAttribute(false)

 

 

ParseChildrenAttribute 不应用于该控件。

 嵌套的(子)元素必须对应于 ASP.NET 服务器控件。页分析器创建子控件并对该控件调用 IParserAccessor.AddParsedSubObject。AddParsedSubObject 的默认实现将子控件添加到该控件的 Controls 集合中。页分析器将标记间的文本分析为 LiteralControl 的实例。

示例:Panel。

 

ParseChildrenAttribute (ChildrenAsProperties = true, DefaultProperty = "PropertyName")

 

ParseChildrenAttribute(true, "PropertyName")

 控件必须定义公共属性名 PropertyName。嵌套的(子)元素必须对应于 PropertyName 属性的子元素。

示例:HtmlTable、HtmlTableRow。

 

有关示例,请参见 ParseChildrenAttribute 示例。

 

ParseChildrenAttribute(false, "PropertyName") 页分析器的这个用法等同于 ParseChildrenAttribute(false)。

 

注意   System.Web.UI.WebControls.WebControl 被标记为 ParseChildren(true)。从 WebControl 派生的自定义控件继承此属性标记。可以通过重新应用具有不同参数的属性来重写继承的属性。

注意   如果除 ParseChildrenAttribute 之外还应用了 ControlBuilderAttribute,则它可以修改在该表中描述的分析逻辑。

2.服务器控件内联模板语法/

指定在支持模板的 ASP.NET 服务器控件中将包括的内容及其排列和样式化方式。

<templatename>
      Server control, data-binding syntax, other valid markup
</templatename>
templatename

ASP.NET 服务器控件模板的名称。

可以使用模板来结构化和样式化 ASP.NET 服务器控件中出现的内容。内联模板语法是处理模板的一种有用方法,因为该语法使您能够以简单的声明语法而不是以编程方式在控件中设计内容的排列和样式。

许多 ASP.NET Web 服务器控件支持模板(例如,RepeaterDataListGridViewFormViewMultiViewLoginViewMenu 控件都支持模板,包括 WebPartZoneCatalogZone 在内的 Web 部件区域控件也支持模板)。请注意,只能为控件声明专门为该控件定义的模板。

模板项必须作为支持它们的服务器控件的子元素进行声明。一个服务器控件可以包含多个模板项,其中每个模板用于指定控件中不同内容的特点。例如,Repeater 控件支持用于指定标题部分、正文或项部分以及脚注部分中内容的布局和外观的模板,还支持用于处理交替项及项之间分隔符的样式的特殊模板。有关详细信息,请参见本主题中的代码示例。

若要指定如何在模板中显示这些内容,请在模板标记中声明其他元素。其他标记可以包括 HTML 标记、ASP.NET 控件以及内联服务器端表达式或代码块。有关如何使用内联模板的更多信息,请参见 ASP.NET Web 服务器控件模板

开发自定义服务器控件时可以定义自己的模板。有关开发定义和使用内联样式模板的控件的更多信息,请参见如何:创建模板化的 ASP.NET 用户控件

下面的代码示例演示如何在 Repeater Web 服务器控件中声明 HeaderTemplateAlternatingItemTemplateItemTemplateFooterTemplate 模板。这些模板中的每一个与 Repeater 类的一个属性关联。

<%@ Page Language="C#" %>
<html>
 <head>
    <script language="C#" runat="server">
       void Page_Load(Object Sender, EventArgs e) {
 
          if (!IsPostBack) {
             ArrayList values = new ArrayList();
 
             values.Add("Apple");
             values.Add("Orange");
             values.Add("Pear");
             values.Add("Banana");
             values.Add("Grape");
 
             Repeater1.DataSource = values;
             Repeater1.DataBind();
          }
       }
    </script>
 
 </head>
 <body>
 
    <h3><font face="Verdana">Repeater Example</font></h3>
 
    <form runat=server>
 
       <b>Repeater1:</b>
       <p>
         
       <asp:Repeater id=Repeater1 runat="server">
             
             
          <HeaderTemplate>
             <table border=1>
          </HeaderTemplate>
 
          <AlternatingItemTemplate>
             <tr>
                <td><b> <%# Container.DataItem %> </b> </td>
             </tr>
          </AlternatingItemTemplate>
 
          <ItemTemplate>
             <tr>
                <td> <%# Container.DataItem %> </td>
             </tr>
          </ItemTemplate>
 
          <FooterTemplate>
             </table>
          </FooterTemplate>
             
       </asp:Repeater>
       <p>
         
    </form>
 </body>
 </html>
Visual Basic
<%@ Page Language="VB" %> 
<html>
<head>
<script language="VB" runat="server">

        Sub Page_Load(Sender As Object, e As EventArgs)
            
            If Not IsPostBack Then
                Dim values As New ArrayList()
                
                values.Add("Apple")
                values.Add("Orange")
                values.Add("Pear")
                values.Add("Banana")
                values.Add("Grape")
                
                Repeater1.DataSource = values
                Repeater1.DataBind()
            End If
        End Sub
</script>
 
 </head>
 <body>
 
    <h3><font face="Verdana">Repeater Example</font></h3>
 
    <form runat=server>
 
       <b>Repeater1:</b>
       <p>
         
       <asp:Repeater id=Repeater1 runat="server">
             
             
          <HeaderTemplate>
             <table border=1>
          </HeaderTemplate>
 
          <AlternatingItemTemplate>
             <tr>
                <td><b> <%# Container.DataItem %> </b> </td>
             </tr>
          </AlternatingItemTemplate>
 
          <ItemTemplate>
             <tr>
                <td> <%# Container.DataItem %> </td>
             </tr>
          </ItemTemplate>
 
          <FooterTemplate>
             </table>
          </FooterTemplate>
             
       </asp:Repeater>
       <p>
         
    </form>
 </body>
 </html>    

3.如何:创建模板化的 ASP.NET 用户控件

如何:创建模板化的 ASP.NET 用户控件

可以创建实现模板的用户控件,这是 ASP.NET 的一项功能,它允许将控件数据与其表示形式相分离。模板化控件不提供用户界面。编写它则是为了实现一个命名容器以及包含属性和方法可由宿主页访问的类。

用户控件的用户界面由页面开发人员在设计时提供。开发人员创建由用户控件定义的类型模板,然后可以向模板添加控件和标记。

创建模板用户控件

  1. 在 .ascx 文件中,添加要在其中显示模板的 ASP.NET PlaceHolder 控件。

  2. 在用户控件的代码中,实现 ITemplate 类型的属性。

  3. 将实现 INamingContainer 接口的服务器控件类定义为要在其中创建模板实例的容器。此容器叫做模板的命名容器。

    说明:

    此控件实质上成了用户控件的嵌套类,但这不是必需的。

  4. TemplateContainerAttribute 应用于实现 ITemplate 的属性 (property),并将模板命名容器的类型作为参数传递给属性 (attribute) 的构造函数。

  5. 在控件的 Init 方法中,将以下步骤重复一次或多次:

    • 创建命名容器类的一个实例。

    • 在命名容器中创建该模板的一个实例。

    • 将命名容器实例添加到 PlaceHolder 服务器控件的 Controls 属性。

      说明:

      从使用用户控件的页面的角度来看,模板化用户控件的语法与自定义模板化控件的语法相同。

下面的示例演示一个模板化用户控件和一个包含该控件的页面。该用户控件创建一个可在宿主页上声明为 <MessageTemplate> 的模板。该模板控件还公开两个可由宿主页在模板内访问的属性:IndexMessage

第一个示例显示模板化用户控件。第二个示例显示包含该用户控件的页面。

Visual Basic
<%@ Control language="VB" ClassName="TemplatedUC" %>
<%@ Import Namespace="System.ComponentModel"  %>

<script runat="server" >
    Private m_messageTemplate As ITemplate = Nothing
    <TemplateContainer(GetType(MessageContainer))> _
    <PersistenceMode(PersistenceMode.InnerProperty)> Public Property _
            MessageTemplate() As ITemplate
        Get
            Return m_messageTemplate
        End Get
        Set(ByVal value As ITemplate)
            m_messageTemplate = Value
        End Set
    End Property
    
    Sub Page_Init()
        If Not (MessageTemplate Is Nothing) Then
            Dim i As Integer
            Dim fruits() As String = _
                {"apple", "orange", "banana", "pineapple"}
            For i = 0 To 3
                Dim container As New MessageContainer(i, fruits(i))
                MessageTemplate.InstantiateIn(container)
                PlaceHolder1.Controls.Add(container)
            Next i
        End If
    End Sub

    Public Class MessageContainer
        Inherits Control
        Implements INamingContainer

        Private m_index As Integer
        Private m_message As String
        Friend Sub New(ByVal i As Integer, ByVal msg As String)
            Me.Index = i
            Me.Message = msg
        End Sub
    
        Public Property Index() As Integer
            Get
                Return m_index
            End Get
            Set(ByVal value As Integer)
                m_index = value
            End Set
        End Property

        Public Property Message() As String
            Get
                Return m_message
            End Get
            Set(ByVal value As String)
                m_message = value
            End Set
        End Property
    End Class
</script>
<asp:Placeholder runat="server" ID="PlaceHolder1" />
<%@ Control language="C#" ClassName="TemplatedUC" %>
<%@ Import Namespace="System.ComponentModel"  %>
<script runat="server">
private ITemplate messageTemplate = null;

[ TemplateContainer(typeof(MessageContainer)) ]
[ PersistenceMode(PersistenceMode.InnerProperty) ]
public ITemplate MessageTemplate {
    get 
    { 
        return messageTemplate; 
    }
    set 
    { 
        messageTemplate = value; 
    }
}

void Page_Init() {
    if (messageTemplate != null) {
        String[] fruits = {"apple", "orange", "banana", "pineapple" };
        for (int i=0; i<4; i++) 
        {
            MessageContainer container = new MessageContainer(i, fruits[i]);
            messageTemplate.InstantiateIn(container);
            PlaceHolder1.Controls.Add(container);
        }
    }
}

public class MessageContainer: Control, INamingContainer {
    private int m_index;
    private String m_message;
    internal MessageContainer(int index, String message)
    { 
        m_index = index;
        m_message = message;
    }
    public int Index {
        get 
        { 
            return m_index; 
        } 
    }
    public String Message 
    { 
        get 
        { 
            return m_message; 
        } 
    }
}
</script>
<asp:Placeholder runat="server" ID="PlaceHolder1" />

Visual Basic
<%@ Page Language="VB" %>
<%@ Register TagPrefix="uc" tagname="TemplateTest" 
    Src="TemplatedUC.ascx" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html >
<script runat="server">
    Sub Page_Load()
        DataBind()
    End Sub
</script>
<head>
<title>Templated User Control Test</title>
</head>
<body>
<h1>Testing Templated User Control</h1>
<form id="Form1" runat="server">
<uc:TemplateTest runat="server">
  <MessageTemplate>
    Index: <asp:Label runat="server" ID="Label1" 
                Text='<%# Container.Index %>' />
    <br />
    Message: <asp:Label runat="server" ID="Label2" 
        Text='<%# Container.Message %>' />
    <hr />
  </MessageTemplate>
</uc:TemplateTest>
</form>
</body>
</html>
<%@ Page Language="C#" %>
<%@ Register TagPrefix="uc" tagname="TemplateTest" 
    Src="TemplatedUC.ascx" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
    "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html >
<script runat="server">
    protected void Page_Load()
    {
        DataBind();
    }
    
</script>
<head>
<title>Templated User Control Test</title>
</head>
<body>
<h1>Testing Templated User Control</h1>
<form id="Form1" runat="server">
<uc:TemplateTest runat="server">
  <MessageTemplate>
    Index: <asp:Label runat="server" ID="Label1" 
        Text='<%# Container.Index %>' />
    <br />
    Message: <asp:Label runat="server" ID="Label2" 
        Text='<%# Container.Message %>' />
    <hr />
  </MessageTemplate>
</uc:TemplateTest>
</form>
</body>
</html>
概念
 
  开发模板化控件的方法:

1.实现 System.Web.UI.INamingContainer 接口.(它可以在控件下创建新的命名范围,这样子控件就在名称树中有了唯一的标识符).
2.将 ParseChildrenAttribute 应用到控件,并传递 true 作为参数.在ASP.NET页上声明性地使用控件时,这样可以指示页分析器如何分析模板属性标记.(也就是说,应用这个元数据属性,可以使页分析器正确的分析模板的属性标记.
[注意:如果控件从WebControl派生,则不用了,因为WebControl已经用该属性作为标记.
3.定义一个或多 System.Web.UI.ITemplate类型的属性.这个属性必须有 System.Web.UI.TemplateContainerAttribute 类型的无数据属性,它指出这个 ITemplate 类型的属性将被哪种 INamingContainer 控件所拥有.(也就是说,用TemplateContainerAttribute元数据属性来标识出控件的模板的容器)
4.为你正在创建的模板化控件创建一个独立的容器控件.(创建这个东西的原因我现在不太清楚,请参见以后关于 模板化数据绑定控件的内容.
5.重写CreateChildControls方法,在模板中创建子控件.
    A.实例化模板容器.
    B.调用模板属性的 InstantiateIn方法并将该容器作为参数传递给它.
    C.将模板容器的示例添加到你的模板化控件的Controls 集合.
示例:
private Control myTemplateContainer;
protected override void CreateChildControls()
{
    if(FirstTemplate != null)
    {
        myTemplateContainer = new FirstTemplateContainer(this);
        FirstTemplate.InstantiateIn(myTemplateContainer);
        Controls.Add(myTemplateContainer);
    }
    else
    {
        Controls.Add(new LiteralControl(Text + " " + DateTime));
    }
}

6.重写从 Control继承的 OnDataBinding 方法:
protected override void OnDataBinding(EventArgs e)
{
    EnsureChildControls();
    base.OnDataBinding(e);
}

EnsureChildControls方法保证在数据绑定之前创建模板中的子控件.
调用基类的 OnDataBinding 方法发确保调用已注册的事件处理程序.

7.对控件中的每一个模板属性执行以上步骤.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值