/*
本章讨论ASP.NET中模板控件的实现。
*/
很多时候控件需要组合一些基础控件来表达一种数据或表达某个业务逻辑,比如DataList,LoginView。
一个应用广泛的控件,需要面对千变万化的需求,只有能被用户定制的界面,才能适应这种变化,因此ASP.NET框架提供了模板(Template)的支持。通过模板功能,用户可以方便地定制控件的UI,而且定制的UI可以方便地嵌入控件处理过程。
8.1 ASP.NET模板概述
ASP.NET框架中有大量基于模板或者支持模板的控件。像DataList、Repeater这样的控件基于模板,也就是说它们需要用户提供模板,而GridView、Login这样的控件提供通用的UI,用户也可以选择使用模板功能定制UI;有的控件只使用模板一次,比如Login的LayoutTemplate和UpdatePanel的ContentTemplate,也有的控件的重复使用模板生成子控件,比如DataList;有的控件有多个模板,甚至模板的数量还不确定,比如GridView,也有的控件只有一个模板,比如UpdateProgress的ProgressTemplate。
但不管模板的使用情况有多么复杂,都是基于ITemplate接口实现的。
8.1.1 ITemplate
对控件来说,模板就是一个ITemplate成员。
System.Web.UI.ITemplate接口只定义了一个方法——InstantiateIn(),用来根据模板实例化控件的内容。
无需担心,InstantiateIn()方法通常不需要你实现,ASP.NET框架会自动完成根据页面源码中的模板内容提供ITemplate实例对象的过程,并自动为你创建InstantiateIn()方法。
所以说,要实现模板只需定义ITemplate类型的属性即可,比如DataList的ItemTemplate:
[TemplateContainer(typeof(DataListItem))
, Browsable(false)
, PersistenceMode (PersistenceMode.InnerProperty)]
public virtual ITemplate ItemTemplate
{
get
{
return this.itemTemplate;
}
set
{
this.itemTemplate = value;
}
}
8.1.2 TemplateContainerAttribute
虽然模板并不一定要绑定数据,但在绝大部分情况下,模板都要绑定数据,所以在使用模板的时候,我们通常会用到这样的语句:
<%# Container.Title %>
<%# DataBinder.Eval(Container.DataItem,“ProductName”) %>
在这些熟悉的绑定表达式中,总是存在Container的身影,那么这个Container是什么呢?
其实这个Container是ITemplate属性上应用的TemplateContainerAttribute来指定的一个模板的容器控件,比如Login的LayoutTemplate模板以Login控件本身为Container:
[TemplateContainer(typeof(Login)),
PersistenceMode(PersistenceMode. InnerProperty),
Browsable(false)]
public virtual ITemplate LayoutTemplate
{
get
{
return this._loginTemplate;
}
set
{
this._loginTemplate = value;
base.ChildControlsCreated = false;
}
}
而GridView中的模板则以GridViewRow为容器:
[TemplateContainer(typeof(GridViewRow)),
Browsable(false),
PersistenceMode (PersistenceMode.InnerProperty)]
public virtual ITemplate EmptyDataTemplate
{
get
{
return this._emptyDataTemplate;
}
set
{
this._emptyDataTemplate = value;
}
}
8.1.3 设计时支持
在前面的章节中,我们了解到ASP.NET框架和Visual Studio对模板的设计时支持也非常到位,而且利用模板设计时功能也非常简单,只需重写控件设计器的TemplateGroups属性即可。







