Asp.net控件开发学习笔记(十一)—-服务器控件模板
在Asp.net 2.0以后的版本,Asp.net提供了服务器控件模板(Template)和数据绑定(Data Bind)来简化开发工作,模板是是用于定制化服务器控件或者HTML如何在页面呈现,而模板和数据绑定往往结合起来在一起实现更高级的功能,比如最经典的GridView.例如,在 GridView服务器控件中可以使用 HTML 元素和控件的组合来创建列表中每行的布局。同样,GridView服务器控件对网格中的每行都具有一个默认的外观。但是,您可以通过为单个行、间隔行、所选行等行定义不同的模板来自定义网格的外观。
定制控件内容
模板用于让开发人员自定义HTML或者服务器控件作为主要控件输出流的一部分。提供了模板的服务器控件其实是给予插入自定义内容提供了容器。
服务器控件模板的强大之处在于它通过让开发人员可以定制输出特定的html来给予了开发人员极高的灵活性.如下图:
使用服务器控件模板
使用服务器控件模板的一大好处是我们可以专注开发空间,而把外观等html和css设置内容让其他人来完成。
在GridView控件里,我们可以通过在ItemTemplate里设置任何我们想设置的内容,在DropDownList控件中我们可以插入ListItem子控件,但在里面插入比如TextBox控件则不行。这个原因就要说到下面一个标签(Attribute)
ParseChildren Attribute
服务器控件必须通过在类声明时添加ParseChildren标签来告诉asp.net页面分析器这个控件需要支持模板。ParseChildren的功能是让服务器控件所含有的子控件作为它的一个属性存在。
对于继承System.Web.UI.WebControls.WebControl基类的控件,这个标签已经通过继承而存在不需要再声明
ParseChildren标签还暴露了ChildrenAsProperties属性,在使用
可以:ParseChildrenAttribute(ChildrenAsProperties = true)
也可以用简便写法:ParseChildren(true)
ChildrenAsProperty属性的作用是让控件的属性和直接在控件内部的html代码,或者说是XML代码(“<”和”>”)进行匹配.如下图:
而不使用ChildrenAsProperties属性的则会是如下图:
下面通过一个Demo来看
Demo 服务器导航菜单
先看Demo的效果
先声明两个用于存放子控件的容器,代码如下:
publicclassBasicTemplateContainer : WebControl, INamingContainer
{
public BasicTemplateContainer(): base(HtmlTextWriterTag.Div)
{
this.BorderWidth = 1;
this.BorderStyle = BorderStyle.Solid;
}
}
publicclassSeperatorTemplateContainer : WebControl, INamingContainer
{
public SeperatorTemplateContainer(): base(HtmlTextWriterTag.Span)
{
}
}
第一个用于存放HeaderTemplate和footerTemplate,而第二个用于存放分隔符
再声明一个存放菜单超链接的容器,代码如下:
[TypeConverter(typeof(ExpandableObjectConverter))]
publicclassMenuItemData
{
public MenuItemData()
{
}
[NotifyParentProperty(true)]
publicstring Title { get; set; }
[NotifyParentProperty(true)]
publicstring Url { get; set; }
[NotifyParentProperty(true)]
publicstring ImageUrl { get; set; }
[NotifyParentProperty(true)]
publicstring Target { get; set; }
}
最后声明一个继承于CompositeControl基类的控件,声明代码如下:
publicclassTemplateMenu : CompositeControl
最终完全代码如下:
TemplateMenu完全代码
1using System;
2using System.Web;
3using System.Web.UI;
4using System.Web.UI.WebControls;
5using System.Collections;
6using System.ComponentModel;
7using System.Web.UI.WebControls;
8namespace bindcontrol
9{
10 [ToolboxData("<{0}:templatemenu runat=server></{0}:templatemenu>")]
11publicclass TemplateMenu : CompositeControl
12 {
13private ArrayList menuData;
14public TemplateMenu(): base()
15 {
16 menuData =new ArrayList(){
17
18new MenuItemData{Title="博客园", Url="http://www.cnblogs.com"},
19new MenuItemData{Title="Microsoft", Url="http://www.microsoft.com"},
20new MenuItemData{Title="ASP.Net", Url="http://asp.net"}};
21 }
22private ITemplate headerTemplate;
23 [Browsable(false), Description("The header template"),
24 PersistenceMode(PersistenceMode.InnerProperty),
25 TemplateContainer(typeof(BasicTemplateContainer))]
26public ITemplate HeaderTemplate
27 {
28get
29 {
30return headerTemplate;
31 }
32set
33 {
34 headerTemplate = value;
35 }
36 }
37private ITemplate footerTemplate;
38 [Browsable(false), Description("The footer template"),
39 PersistenceMode(PersistenceMode.InnerProperty),
40 TemplateContainer(typeof(BasicTemplateContainer))]
41public ITemplate FooterTemplate
42 {
43get
44 {
45return footerTemplate;
46 }
47set
48 {
49 footerTemplate = value;
50 }
51 }
52private ITemplate separatorTemplate;
53 [Browsable(false), Description("The separator template"),
54 PersistenceMode(PersistenceMode.InnerProperty),
55 TemplateContainer(typeof(SeperatorTemplateContainer))]
56public ITemplate SeparatorTemplate
57 {
58get
59 {
60return separatorTemplate;
61 }
62set
63 {
64 separatorTemplate = value;
65 }
66 }
67privatevoid CreateControlHierarchy()
68 {
69if (HeaderTemplate !=null)
70 {
71 BasicTemplateContainer header =new BasicTemplateContainer();
72 HeaderTemplate.InstantiateIn(header);
73 Controls.Add(header);
74 }
75int count = menuData.Count;
76for (int index =0; index < count; index++)
77 {
78 MenuItemData itemdata = (MenuItemData)menuData[index];
79 HyperLink link =new HyperLink()
80 {
81 Text = itemdata.Title,
82 NavigateUrl = itemdata.Url,
83 ImageUrl = itemdata.ImageUrl,
84 Target = itemdata.Target
85 };
86 Controls.Add(link);
87if (index != count –1)
88 {
89if (SeparatorTemplate !=null)
90 {
91 SeperatorTemplateContainer separator =new SeperatorTemplateContainer();
92 SeparatorTemplate.InstantiateIn(separator);
93 Controls.Add(separator);
94 }
95else
96 {
97 Controls.Add(new LiteralControl(" | "));
98 }
99 }
100 }
101if (FooterTemplate !=null)
102 {
103 BasicTemplateContainer footer =new BasicTemplateContainer();
104 FooterTemplate.InstantiateIn(footer);
105 Controls.Add(footer);
106 }
107 }
108overrideprotectedvoid CreateChildControls()
109 {
110 Controls.Clear();
111 CreateControlHierarchy();
112 }
113publicoverride ControlCollection Controls
114 {
115get
116 {
117 EnsureChildControls();
118returnbase.Controls;
119 }
120 }
121 }
122
123publicclass BasicTemplateContainer : WebControl, INamingContainer
124 {
125public BasicTemplateContainer(): base(HtmlTextWriterTag.Div)
126 {
127this.BorderWidth =1;
128this.BorderStyle = BorderStyle.Solid;
129 }
130 }
131publicclass SeperatorTemplateContainer : WebControl, INamingContainer
132 {
133public SeperatorTemplateContainer(): base(HtmlTextWriterTag.Span)
134 {
135 }
136 }
137 [TypeConverter(typeof(ExpandableObjectConverter))]
138publicclass MenuItemData
139 {
140public MenuItemData()
141 {
142 }
143 [NotifyParentProperty(true)]
144publicstring Title { get; set; }
145 [NotifyParentProperty(true)]
146publicstring Url { get; set; }
147 [NotifyParentProperty(true)]
148publicstring ImageUrl { get; set; }
149 [NotifyParentProperty(true)]
150publicstring Target { get; set; }
151 }
152}
前台调用代码如下:
首先注册控件:<%@Register Namespace="bindcontrol"TagPrefix="dd"%>
然后是前台代码:
<dd:TemplateMenurunat="server">
<HeaderTemplate>template header</HeaderTemplate>
<SeparatorTemplate>%</SeparatorTemplate>
<FooterTemplate>template footer</FooterTemplate>
</dd:TemplateMenu>
注意,作为模板的类型必须声明成ITemplate类型,而这个ITemplate的具体类型则通过TemplateContainer标签进行注入.我们通过声明CreateControlHierarchy()函数来进行控制控件的具体输出,最后通过覆盖父类的CreateChildControls()方法来调用我们写好的CreateControlHierarchy方法达到控制输出的目的。
最后,你可能有疑问,那个神奇的ChildrenAsProperties属性跑哪去了?如果没有这个属性,那上面<headerTemplate>之类的标签又是如何匹配的呢?还记得吗,继承与WebControl基类的控件继承了这个标签,所以不用显示声明,所以ChildrenAsProperties属性come for free:-)
http://www.cnblogs.com/CareySon/archive/2009/10/19/1586146.html