在Asp.net 2.0以后的版本,Asp.net提供了服務器控件模板(Template)和數(shù)據(jù)綁定(Data Bind)來簡化開發(fā)工作,模板是是用于定制化服務器控件或者HTML如何在頁面呈現(xiàn),而模板和數(shù)據(jù)綁定往往結合起來在一起實現(xiàn)更高級的功能,比如最經典的GridView.例如,在 GridView服務器控件中可以使用 HTML 元素和控件的組合來創(chuàng)建列表中每行的布局。同樣,GridView服務器控件對網格中的每行都具有一個默認的外觀。但是,您可以通過為單個行、間隔行、所選行等行定義不同的模板來自定義網格的外觀。
定制控件內容
模板用于讓開發(fā)人員自定義HTML或者服務器控件作為主要控件輸出流的一部分。提供了模板的服務器控件其實是給予插入自定義內容提供了容器。
服務器控件模板的強大之處在于它通過讓開發(fā)人員可以定制輸出特定的html來給予了開發(fā)人員極高的靈活性.如下圖:
使用服務器控件模板
使用服務器控件模板的一大好處是我們可以專注開發(fā)空間,而把外觀等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的效果
先聲明兩個用于存放子控件的容器,代碼如下:
public class BasicTemplateContainer : WebControl, INamingContainer
{
public BasicTemplateContainer(): base(HtmlTextWriterTag.Div)
{
this.BorderWidth = 1;
this.BorderStyle = BorderStyle.Solid;
}
}
public class SeperatorTemplateContainer : WebControl, INamingContainer
{
public SeperatorTemplateContainer(): base(HtmlTextWriterTag.Span)
{
}
}
第一個用于存放HeaderTemplate和footerTemplate,而第二個用于存放分隔符
再聲明一個存放菜單超鏈接的容器,代碼如下:
[TypeConverter(typeof(ExpandableObjectConverter))]
public class MenuItemData
{
public MenuItemData()
{
}
[NotifyParentProperty(true)]
public string Title { get; set; }
[NotifyParentProperty(true)]
public string Url { get; set; }
[NotifyParentProperty(true)]
public string ImageUrl { get; set; }
[NotifyParentProperty(true)]
public string Target { get; set; }
}
最后聲明一個繼承于CompositeControl基類的控件,聲明代碼如下:
public class TemplateMenu : CompositeControl
最終完全代碼如下:

TemplateMenu完全代碼
1 using System;
2 using System.Web;
3 using System.Web.UI;
4 using System.Web.UI.WebControls;
5 using System.Collections;
6 using System.ComponentModel;
7 using System.Web.UI.WebControls;
8 namespace bindcontrol
9 {
10 [ToolboxData("<{0}:templatemenu runat=server></{0}:templatemenu>")]
11 public class TemplateMenu : CompositeControl
12 {
13 private ArrayList menuData;
14 public TemplateMenu(): base()
15 {
16 menuData = new ArrayList(){
17
18 new MenuItemData{Title="博客園", Url="//www.cnblogs.com"},
19 new MenuItemData{Title="Microsoft", Url="//www.microsoft.com"},
20 new MenuItemData{Title="ASP.Net", Url="//asp.net"}};
21 }
22 private ITemplate headerTemplate;
23 [Browsable(false), Description("The header template"),
24 PersistenceMode(PersistenceMode.InnerProperty),
25 TemplateContainer(typeof(BasicTemplateContainer))]
26 public ITemplate HeaderTemplate
27 {
28 get
29 {
30 return headerTemplate;
31 }
32 set
33 {
34 headerTemplate = value;
35 }
36 }
37 private ITemplate footerTemplate;
38 [Browsable(false), Description("The footer template"),
39 PersistenceMode(PersistenceMode.InnerProperty),
40 TemplateContainer(typeof(BasicTemplateContainer))]
41 public ITemplate FooterTemplate
42 {
43 get
44 {
45 return footerTemplate;
46 }
47 set
48 {
49 footerTemplate = value;
50 }
51 }
52 private ITemplate separatorTemplate;
53 [Browsable(false), Description("The separator template"),
54 PersistenceMode(PersistenceMode.InnerProperty),
55 TemplateContainer(typeof(SeperatorTemplateContainer))]
56 public ITemplate SeparatorTemplate
57 {
58 get
59 {
60 return separatorTemplate;
61 }
62 set
63 {
64 separatorTemplate = value;
65 }
66 }
67 private void CreateControlHierarchy()
68 {
69 if (HeaderTemplate != null)
70 {
71 BasicTemplateContainer header = new BasicTemplateContainer();
72 HeaderTemplate.InstantiateIn(header);
73 Controls.Add(header);
74 }
75 int count = menuData.Count;
76 for (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);
87 if (index != count - 1)
88 {
89 if (SeparatorTemplate != null)
90 {
91 SeperatorTemplateContainer separator = new SeperatorTemplateContainer();
92 SeparatorTemplate.InstantiateIn(separator);
93 Controls.Add(separator);
94 }
95 else
96 {
97 Controls.Add(new LiteralControl(" | "));
98 }
99 }
100 }
101 if (FooterTemplate != null)
102 {
103 BasicTemplateContainer footer = new BasicTemplateContainer();
104 FooterTemplate.InstantiateIn(footer);
105 Controls.Add(footer);
106 }
107 }
108 override protected void CreateChildControls()
109 {
110 Controls.Clear();
111 CreateControlHierarchy();
112 }
113 public override ControlCollection Controls
114 {
115 get
116 {
117 EnsureChildControls();
118 return base.Controls;
119 }
120 }
121 }
122
123 public class BasicTemplateContainer : WebControl, INamingContainer
124 {
125 public BasicTemplateContainer(): base(HtmlTextWriterTag.Div)
126 {
127 this.BorderWidth = 1;
128 this.BorderStyle = BorderStyle.Solid;
129 }
130 }
131 public class SeperatorTemplateContainer : WebControl, INamingContainer
132 {
133 public SeperatorTemplateContainer(): base(HtmlTextWriterTag.Span)
134 {
135 }
136 }
137 [TypeConverter(typeof(ExpandableObjectConverter))]
138 public class MenuItemData
139 {
140 public MenuItemData()
141 {
142 }
143 [NotifyParentProperty(true)]
144 public string Title { get; set; }
145 [NotifyParentProperty(true)]
146 public string Url { get; set; }
147 [NotifyParentProperty(true)]
148 public string ImageUrl { get; set; }
149 [NotifyParentProperty(true)]
150 public string Target { get; set; }
151 }
152 }
前臺調用代碼如下:
首先注冊控件:<%@ Register Namespace="bindcontrol" TagPrefix="dd" %>
然后是前臺代碼:
<dd:TemplateMenu runat="server" >
<HeaderTemplate>template header</HeaderTemplate>
<SeparatorTemplate>%</SeparatorTemplate>
<FooterTemplate>template footer</FooterTemplate>
</dd:TemplateMenu>
注意,作為模板的類型必須聲明成ITemplate類型,而這個ITemplate的具體類型則通過TemplateContainer標簽進行注入.我們通過聲明CreateControlHierarchy()函數(shù)來進行控制控件的具體輸出,最后通過覆蓋父類的CreateChildControls()方法來調用我們寫好的CreateControlHierarchy方法達到控制輸出的目的。
最后,你可能有疑問,那個神奇的ChildrenAsProperties屬性跑哪去了?如果沒有這個屬性,那上面<headerTemplate>之類的標簽又是如何匹配的呢?還記得嗎,繼承與WebControl基類的控件繼承了這個標簽,所以不用顯示聲明,所以ChildrenAsProperties屬性come for free:-)
標簽:
本站文章除注明轉載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉載,但請務必注明出處、不得修改原文相關鏈接,如果存在內容上的異議請郵件反饋至chenjj@fc6vip.cn
文章轉載自:博客園