.NET复合控件开发随笔(一)

使用.NET一年多了,前不久开始迷上了.NET的控件开发,发觉这真是一个表现创造力的工作:)。

前不久应公司要求写一个在公司网站全站通用的留言本,因为公司旗下网站(www.163888.net)内容比较庞杂,而且时常会出现各种活动,留言本的使用频率非常高,而原先的方法是每次活动都从新开发一个留言本,实在是非常不科学的方式,而实际上每个留言本的逻辑处理基本上是一致的,因此才有了开发一个全站通用的留言本的想法。

任务到手之后,思考实现时,第一个想到了动态调用.ascx文件的方式来写一个复合控件,但是经过再三考虑之后,发觉这个方法存在不少问题。

虽然它达到了同一逻辑结构,灵活换肤的需求,但是正如我先前所说留言本在本站使用频率很高,这样每次使用都会产生1-2个.ascx文件,感觉上有点累赘。

经过再三考虑,无意中想到了Repeater这个控件,它使用ItemTemplate和AlternatingItemTemplate两个属性灵活包含模板而不产生.ascx文件,这不正是我所需要的吗?我何不写一个控件内部绑定数据的类似Repeater的控件?

有了这个想法之后,立刻使用Reflector打开了System.Web.dll找到了Repeater控件,参考着完成了下面的GuestBook控件。

 

  1using System;
  2using System.Web.UI;
  3using System.Web.UI.WebControls;
  4using System.ComponentModel;
  5using System.Collections;
  6using SunBird.Controls;
  7using SunBird.Components;
  8
  9namespace SunBird.GuestBookControl
 10{
 11    [ParseChildren(true), PersistChildren(false)]
 12    public class GuestBook : Control , INamingContainer
 13    {
 14        ITemplate itemTemplate;
 15        [DefaultValue((string)null), PersistenceMode(PersistenceMode.InnerProperty), TemplateContainer(typeof(GuestBookItem)), Browsable(false)]
 16        public ITemplate ItemTemplate
 17        {
 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 AlternatingItemTemplate
 25        {
 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 PagerTemplate
 33        {
 34            get return pagerTemplate; }
 35            set { pagerTemplate = value; }
 36        }

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

 45
 46        int type;
 47        public int Type
 48        {
 49            get return type; }
 50            set { type = value; }
 51        }

 52
 53        int markup;
 54        public int Markup
 55        {
 56            get return markup; }
 57            set { markup = value; }
 58        }

 59
 60        int top;
 61        public int Top
 62        {
 63            get return top; }
 64            set { top = value; }
 65        }

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

 73
 74        int superUser;
 75        public int SuperUser
 76        {
 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        DataBind
115
116        OnDataBinding
124
125        CreatePagerTemplate
142
143        CreateDataItemTemplate
184
185        GuestBook_ItemDataBound
278
279        GBDelPost_Command
292    }

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 (基类) 它定义了大部分的功能。

 

 1using System;
 2using System.Web.UI.WebControls;
 3using SunBird.Components;
 4
 5namespace SunBird.GuestBookControl
 6{
 7    public class GuestBookCreateBase : GuestBookSkinBase
 8    {
 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        AttachChildCotrols
38
39        CreateButton_Click
67
68        int type;
69        public virtual int Type
70        {
71            get return type; }
72            set { type = value; }
73        }

74
75        int markup;
76        public virtual int Markup
77        {
78            get return markup; }
79            set { markup = value; }
80        }

81    }

82}

 

2、CreatePostNeedLogin : GuestBookCreateBase 需要登录,他实际上只是override了基类的CreateButton_Click方法,为该方法加入了验证登录的操作。

 

 1using System;
 2using System.Web.UI.WebControls;
 3using SunBird.Components;
 4
 5namespace SunBird.GuestBookControl
 6{
 7    public class CreatePostNeedLogin : GuestBookCreateBase
 8    {
 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                else
46                {
47                    Globals.OutMessage("用户名或密码错误。");
48                    return;
49                }

50            }

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

55
56    }

57}

 

3、CreatePostNotNeedLogin : GuestBookCreateBase 不需要登录,实际上该类没有做任何操作仅仅只是为了方便其他人使用。

 

 1using System;
 2using System.Web.UI.WebControls;
 3
 4namespace SunBird.GuestBookControl
 5{
 6    public class CreatePostNotNeedLogin : GuestBookCreateBase
 7    {
 8        protected override void AttachChildControls()
 9        {
10            base.AttachChildControls();
11
12
13        }

14    }

15}

 

控件的核心的类差不多就这几个,完整的代码如果有兴趣,请下载附件查看。

终于找到上传附件的地方了,下面是源代码,有兴趣的朋友可以下载看看,如果你有更好的方法请一定告诉我。

GuestBookControl源代码

posted @ 2006-04-06 09:38  阿蒙  阅读(1174)  评论(3编辑  收藏  举报