.NET复合控件开发随笔(一)
使用.NET一年多了,前不久开始迷上了.NET的控件开发,发觉这真是一个表现创造力的工作:)。
前不久应公司要求写一个在公司网站全站通用的留言本,因为公司旗下网站(www.163888.net)内容比较庞杂,而且时常会出现各种活动,留言本的使用频率非常高,而原先的方法是每次活动都从新开发一个留言本,实在是非常不科学的方式,而实际上每个留言本的逻辑处理基本上是一致的,因此才有了开发一个全站通用的留言本的想法。
任务到手之后,思考实现时,第一个想到了动态调用.ascx文件的方式来写一个复合控件,但是经过再三考虑之后,发觉这个方法存在不少问题。
虽然它达到了同一逻辑结构,灵活换肤的需求,但是正如我先前所说留言本在本站使用频率很高,这样每次使用都会产生1-2个.ascx文件,感觉上有点累赘。
经过再三考虑,无意中想到了Repeater这个控件,它使用ItemTemplate和AlternatingItemTemplate两个属性灵活包含模板而不产生.ascx文件,这不正是我所需要的吗?我何不写一个控件内部绑定数据的类似Repeater的控件?
有了这个想法之后,立刻使用Reflector打开了System.Web.dll找到了Repeater控件,参考着完成了下面的GuestBook控件。
using System;2
using System.Web.UI;3
using System.Web.UI.WebControls;4
using System.ComponentModel;5
using System.Collections;6
using SunBird.Controls;7
using SunBird.Components;8

9
namespace SunBird.GuestBookControl10
{11
[ParseChildren(true), PersistChildren(false)]12
public class GuestBook : Control , INamingContainer13
{14
ITemplate itemTemplate;15
[DefaultValue((string)null), PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(GuestBookItem)), Browsable(false)]16
public ITemplate ItemTemplate17
{18
get { return itemTemplate; }19
set { itemTemplate = value; }20
}21

22
ITemplate alternatingItemTemplate;23
[DefaultValue((string)null), PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(GuestBookItem)), Browsable(false)]24
public ITemplate AlternatingItemTemplate25
{26
get { return alternatingItemTemplate; }27
set { alternatingItemTemplate = value; }28
}29

30
ITemplate pagerTemplate;31
[DefaultValue((string)null), PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(GuestBookItem)), Browsable(false)]32
public ITemplate PagerTemplate33
{34
get { return pagerTemplate; }35
set { pagerTemplate = value; }36
}37

38
object dataSource;39
[Browsable(false)]40
public object DataSource41
{42
get { return dataSource; }43
set { dataSource = value; }44
}45

46
int type;47
public int Type48
{49
get { return type; }50
set { type = value; }51
}52

53
int markup;54
public int Markup55
{56
get { return markup; }57
set { markup = value; }58
}59

60
int top;61
public int Top62
{63
get { return top; }64
set { top = value; }65
}66

67
int pageSize;68
public int PageSize69
{70
set { pageSize = value; }71
get { return pageSize <= 0 ? 10 : pageSize;}72
}73

74
int superUser;75
public int SuperUser76
{77
get 78
{ 79
if (superUser <= 0)80
return -1;81
return superUser;82
}83
set { superUser = value; }84
}85

86

87
protected override void OnLoad(EventArgs e)88
{89
base.OnLoad (e);90
if (!Page.IsPostBack)91
{92
DataBind();93
}94
}95

96
DataBind115

116
OnDataBinding124

125
CreatePagerTemplate142

143
CreateDataItemTemplate184

185
GuestBook_ItemDataBound278

279
GBDelPost_Command292
}293
}
如果使用这样一个控件,在页面注册之后只需要使用它的ItemTemplate和AlternatingItemTemplate属性就可以加载模板了,比原先设想的动态加载.ascx文件的方式要好得多,如:
<% @ Register TagPrefix="GB" Namespace="SunBird.GuestBookControl" Assembly="SunBird.GuestBook" %>
<GB:GuestBook id="guestBook" runat="server" Type="0" Markup="0">
<ItemTemplate>
模板代码
</ItemTemplate>
<AlternatingItemTemplate>
奇数行模板代码
</AlternatingItemTemplate>
<PagerTemplate /> <!-- 分页 -->
</GB:GuestBook>
这样就完成了该控件的定义,PagerTemplate属性是分页显示。
下面是留言本信息的发布,发不分两种:1、需要登录,2、不需要登录。
于是分别写了三个控件类:
1、GuestBookCreateBase (基类) 它定义了大部分的功能。
using System;2
using System.Web.UI.WebControls;3
using SunBird.Components;4

5
namespace SunBird.GuestBookControl6
{7
public class GuestBookCreateBase : GuestBookSkinBase8
{9
public override void DataBind()10
{11
base.DataBind();12
}13

14
protected override void OnLoad(EventArgs e)15
{16
base.OnLoad(e);17
if (!Page.IsPostBack)18
{19
DataBind();20
}21
}22

23
AttachChildCotrols38

39
CreateButton_Click67

68
int type;69
public virtual int Type70
{71
get { return type; }72
set { type = value; }73
}74

75
int markup;76
public virtual int Markup77
{78
get { return markup; }79
set { markup = value; }80
}81
}82
}
2、CreatePostNeedLogin : GuestBookCreateBase 需要登录,他实际上只是override了基类的CreateButton_Click方法,为该方法加入了验证登录的操作。
using System;2
using System.Web.UI.WebControls;3
using SunBird.Components;4

5
namespace SunBird.GuestBookControl6
{7
public class CreatePostNeedLogin : GuestBookCreateBase8
{9
protected TextBox UserName;10
protected TextBox UserPassword;11
protected override void AttachChildControls()12
{13
base.AttachChildControls();14

15
UserName = (TextBox)FindControl("UserName");16
UserPassword = (TextBox)FindControl("UserPassword");17
}18

19
protected override void CreateButton_Click(object sender, EventArgs e)20
{21
User user = UContext.Current.User;22
if (user.IsAnonymous)23
{24
if (Globals.IsNullorEmpty(UserName.Text))25
{26
Globals.OutMessage("请输入用户名。");27
return;28
}29
if (Globals.IsNullorEmpty(UserPassword.Text))30
{31
Globals.OutMessage("请输入密码。");32
return;33
}34

35
int userId;36
string name = UserName.Text;37
string password = NewBase.String.GetMd5(UserPassword.Text);38
bool result = GuestBookDataProvider.Instance().ValidateUser(name, password, out userId);39
if (result)40
{41
user.UserID = userId;42
user.UserName = name;43
Users.SaveUserCookie(user);44
}45
else46
{47
Globals.OutMessage("用户名或密码错误。");48
return;49
}50
}51

52

53
base.CreateButton_Click (sender, e); 54
}55

56
}57
}
3、CreatePostNotNeedLogin : GuestBookCreateBase 不需要登录,实际上该类没有做任何操作仅仅只是为了方便其他人使用。
using System;2
using System.Web.UI.WebControls;3

4
namespace SunBird.GuestBookControl5
{6
public class CreatePostNotNeedLogin : GuestBookCreateBase7
{8
protected override void AttachChildControls()9
{10
base.AttachChildControls();11

12

13
}14
}15
}
控件的核心的类差不多就这几个,完整的代码如果有兴趣,请下载附件查看。
终于找到上传附件的地方了,下面是源代码,有兴趣的朋友可以下载看看,如果你有更好的方法请一定告诉我。



浙公网安备 33010602011771号