第五章 模板控件开发
系列文章链接:
ASP.NET自定义控件组件开发 第二章 继承WebControl的自定义控件
ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇
ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇
ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl
ASP.NET自定义控件组件开发 第四章 组合控件开发CompositeControl 后篇 --事件冒泡
大家好,我们今天来开发一个模板控件。
其实开发一个模板控件比开发一个组合控件更加简单,所以这章不难。
开发一个模板控件一般都继承CompositeControl,因为继承这个基类后,我们就省却了很多的麻烦。所以本章我们开
发的模板控件也继承于CompositeControl。大家应该还记得我们上章开发那个登录Login控件吧,如下:
以上就是我们之前开发的登录控件,现在我们来改造它。我们的现在的这个登录控件的输入用户名和密码的控件是
TextBox,我们有时候可能想把TextBox 换成DropdownList,或者其他的控件。也就说,我们想定制这个登录的控件。那
么,我们就要模板了。
首先来看看我们本章实现控件的最后效果:
大家看见没,这样我们就可以定制这个控件了。好了,我们来实现吧。
首先,我们让我们的模板控件继承上章的那个组合的Login控件:


1 public class TemplateLoginControl:Login
然后,我们就声明我们的模板:


1 #region//声明模板
2 private ITemplate loginUserNameTemplate;
3
4 [Browsable (false )]//我们不想在属性窗口中看见它
5 [TemplateContainer (typeof(TemplateLoginControl ))]//我们的模板是包含在找个控件中的,
6 [PersistenceMode (PersistenceMode.InnerProperty )]//模板中内容很复杂的,比如你可以拖入很多的控件
7 public ITemplate LoginUserNameTemplate
8 {
9 get
10 {
11 return loginUserNameTemplate;
12 }
13 set
14 {
15 loginUserNameTemplate = value;
16 }
17
18 }
19
20 private ITemplate loginUserPasswardTemplate;
21 [Browsable(false)]//我们不想在属性窗口中看见它
22 [TemplateContainer(typeof(TemplateLoginControl))]//我们的模板是包含在找个控件中的,
23 [PersistenceMode(PersistenceMode.InnerProperty)]//模板中内容很复杂的,比如你可以拖入很多的控件
24 public ITemplate LoginUserPasswardTemplate
25 {
26 get
27 {
28 return loginUserPasswardTemplate;
29 }
30 set
31 {
32 loginUserPasswardTemplate = value;
33 }
34 }
35 #endregion
正如前面所说的,我们只是想定制两个输入信息的模板,大家可以根据需要,声明更多的模板。如,大家还可以
把显示的用户名的那些Label换成模板定制。
其实编写模板控件比编写一个组合控件更加的简单。大家稍后就可以体会到了。
好了,声明完了模板之后,我们的控件写了一大半了,还差一点。大家想想是什么???
对了,就是应用这些模板了。如下:


1 protected override void CreateChildControls()
2 {
3 Controls.Clear();
4 if (loginUserNameTemplate != null)
5 loginUserNameTemplate.InstantiateIn(this);
6 else
7 base.CreateChildControls();
8 if(loginUserPasswardTemplate!=null )
9 loginUserPasswardTemplate .InstantiateIn(this);
10 else
11 base.CreateChildControls();
12
13 ChildControlsCreated = true;
14
15
16 }
我想,大家对这个方法不陌生。因为我们之前的组合控件也是重写了这个方法。到这里,就写完了。
大家可能还有疑问,为什么这样重写 CreateChildControls()方法后,就会达到我们的效果?
下面,我就来将这个方法和之前的那个组合控件的 CreateChildControls()方法比较一下,也顺便讲下
模板的内幕。
先看组合控件的 CreateChildControls()方法,见下:


1 protected override void CreateChildControls()
2 {
3 Controls.Clear();
4
5 //初始化控件lbUserName
6 lbUserName = new Label();
7 lbUserName.Text = "用户名:";
8 lbUserName.ID = "lbUserName";
9 //把控件添加到我们的组合控件中
10 Controls.Add(lbUserName);
11
12 //初始化控件lbUserPassward
13 lbUserPassward = new Label();
14 lbUserPassward.Text = "密 码:";
15 lbUserPassward.ID = "lbUserPassward";
16 Controls.Add(lbUserPassward);
17
18
19 txtUserName = new TextBox();
20 txtUserName.ID = "txtUserName";
21 txtUserName.Width = Unit.Percentage(60);
22 Controls.Add(txtUserName);
23
24 txtUserPassward = new TextBox();
25 txtUserPassward.ID = "txtUserPassward";
26 txtUserPassward.Width = Unit.Percentage(60);
27 Controls.Add(txtUserPassward);
28
29 submitButton = new Button();
30 submitButton.Text = "提交";
31 submitButton.CommandName = "Validate";
32 Controls.Add(submitButton);
33
34 ChildControlsCreated = true;
35 }
1.首先,在之前的组合控件中,我们是把那个TextBox,Label硬编码到了生成和初始化控件的方法
CreateChildControls()中。而在模板控件中,我们没有这样做,我们只是简单的调用了模板的一个方法:
InstantiateIn()。实际上,这个方法是个晚绑定。
为什么是晚绑定?先来看看下面:
假设我们想用个下拉框来输入用户名,我们肯定要设计下拉框的属性,如 name,id,等等,当我们设置好
后,就形如这样了:


1 <asp:DropDownList ID="mylist" runat="server" BackColor ="red" ></asp:DropDownList>
其实这样和在 CreateChildControls()中声明是一样的,形如:


1 DropDownList mylist = new DropDownList();
2 mylist.ID = "mylist";
3 mylist.Items = new ListItemCollection();
4 Controls.Add(mylist);
5
其实模板控件的方法InstantiateIn()就是将之前的那个<ASp:dropdownlist....>代码转换为
DropDownList mylist=new DropDownList()...
不知道大家清楚,说到底就是个晚绑定!!!
到这里,模板控件完了,大家编译后,就后看到下面的控件:
然后,我们就在html代码开发声明:如下:


1 <cc1:TemplateLoginControl ID="TemplateLoginControl1" runat="server">
2 <LoginUserNameTemplate >
3
4 </LoginUserNameTemplate>
5 <LoginUserPasswardTemplate>
6
7 </LoginUserPasswardTemplate>
8 </cc1:TemplateLoginControl>
9
很多时候,我们不喜欢这样,因为我们更加喜欢图形化的设置,如下:
这样更加友好些。其实这也不难,只要加个设计器就可以了。
设计器是个类。在ASP.NET有很多的设计器,如ControlDesigner,CompositeControlDesigner.等等。
我们的设计器的一般都继承已有的设计器类。在这里我不多讲,大家需要的话,我专们用一章来讲。


1

2



3

4



5

6

7

8

9

10



11

12

13



14

15



16

17

18

19

20

21



22

23

24

25

26

27

28

29

30



31

32



33

34



35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

然后在这样:


1 [Designer (typeof (MyLoginDesigner ))]
2 public class TemplateLoginControl:Login
一切就OK了,写的有些催促,大家有问题我一定回复。
完整代码如下:


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16



17

18

19



20


21

22

23

24

25

26

27



28

29



30

31

32

33



34

35

36

37

38

39

40

41

42

43

44



45

46



47

48

49

50



51

52

53

54

55


56

57

58



59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82



83

84



85

86

87

88

89

90



91

92

93



94

95



96

97

98

99

100

101



102

103

104

105

106

107

108

109

110



111

112



113

114



115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

.