All articles| All Pictures| All Softwares| All Video| Go home page| Write articles| Upload pictures

Reading number is top 10 articles
ASP.NET2.0自动搜索文件组成导航系统_.net资料_编程技术
Asp.Net小技巧之在client端调用server端事件_.net资料_编程技术
PHP实例:用PHP将mysql数据表转换为excel文件格式_[PHP教程]
Sqlserver如何创建语言辅助函数_[SQL,Server教程]
数据库死锁导致网站站点访问不了之解决方案_[SQL,Server教程]
ASP.NET,2.0的异步页面刷新_[Asp.Net教程]
Silverlight,2,(beta1)数据操作(6)——使用LINQ,to,SQL进行数据_[Asp.Net教程]
AJAX实例入门_[AJAX教程]
PHP:实现给上传图片加水印的程序代码_php资料_编程技术
Asp.net给站点某目录增加Aspnet用户_[Asp.Net教程]
Reading number is top 10 pictures
The money of more than 100 countries and regions18
这只猪到底犯了什么错?
9.3阅兵全景图2-英雄连队梯队和外国方阵梯队
美丽的桂林风光1
壮丽的云彩2
美洲杯宝贝的雨中风情2
A man's favorite things6
王艳写真温柔如水2
The woman fight much more than men
什么叫国家
Download software ranking
Boxer's Top ten classic battle1
天龙八部十二宫服务端
Eclipse-CALMSANNY (second edition)
Tram sex maniac 2 (H) rar bag2
Unix video tutorial13
linux安装大全
C++教程第四版
matrix1
Unix video tutorial1
Unix video tutorial6
归海一刀 published in(发表于) 2014/1/30 1:01:26 Edit(编辑)
Discuz!NT控件剖析,之,DataGrid(数据列表),[原创-,附源码]_[Asp.Net教程]

Discuz!NT控件剖析,之,DataGrid(数据列表),[原创-,附源码]_[Asp.Net教程]

Discuz!NT控件剖析 之 DataGrid(数据列表) [原创: 附源码]_[Asp.Net教程]

自从 9月未开始写关于"ICONIX方法"的系列文章以来,到今天已有两个多月了,当初因为兴趣点的转移才划一
段落的Discuz!NT 系列文章,从今天开始又要开始续写了。这写这个系列以来,大家对我写的内容也是包贬不一,
其实这也是众口难调所致,我会在接下来的几篇随笔中尽力顾及大家的感受和阅读口味。最后还是希望大家能支持我们


的这个开源项目。


好了,开始今天的话题!


先请大家看一下这个控件运行时的效果图:


效果图1: datagrid_1.JPG


效果图2: datagrid_2.JPG




需要说明的是写这个控件(继承自.net DataGrid 控件)的动机:

其实在产品早期,为了提高开发速度。我们最先使用的是Component Art 控件库中的DataGrid控件,相信园子
里肯定有人用过这个商业控件库,甚至研究过它。从我个人感受看,我只能是“NB”来形容它了,首先是它的使用习惯
和方法名称非常接近(甚至完全相同)于我们所熟悉的Microsoft .NET DataGrid 控件,另外就是它的功能比微软
的DataGrid强大得不是一点半点,是那种“很好很强大”的东东。我在这里要向那些致力于控件开发的朋友推荐这个
控件库,相信大家会从它的源码中学到很多有益的东西。

如果这里有些朋友还不知道它的话,建议大家看看 CS(这里可不是"反恐精英"呀),这个开源社区软件里的控件
库就用的是Component Art。


言归正传吧,因为Component Art是商业控件库,如果使用的话会有许多问题(如授权等)。所以在Discuz!NT
1.0 正式版推出前, 我们的相应代码基本上都又再次回到了 Microsoft .NET DataGrid上了,同时考虑到所开发的
代码要适用于.net1.0-.net2.0,所以没有使用.net2.0中的DataView控件。

即然决定使用Microsoft .NET DataGrid,那么就要看看它到底适不适合我们这个项目了:) ,因为之前已完成
了后台的编码工作,而剩下的就是在确保少修改代码,甚至减少代码量的基础上使用这个控件来摆脱Component Art。


在减少代码量的方面,这里对“原始”的DataGrid进行了不少的封装, 如下:


1.绑定数据部分,为了实现只给一条 SQL语句,就完成数据绑定的设计,我在继承自DataGrid的类中写了如下
方法:


1//添加表类型对象
2 public void BindData(string sqlstring)
3 {
4 this.SqlText = sqlstring;
5
6 //DbHelper类我在之前的关于数据库链接一文中已介绍过,大家可以参考一下
7 DataTable dt = DbHelper.ExecuteDataset(CommandType.Text, sqlstring).Tables[0];
8
9 //用于标识记录数
10 this.VirtualItemCount = dt.Rows.Count;
11
12 //下面两行代码就不用多说了吧:)
13 this.DataSource = dt;
14 this.DataBind();
15 }
16
17 public void BindData()
18 {
19 if ((this.SqlText != null) && (this.SqlText != ""))
20 {
21 BindData(this.SqlText);
22 }
23
24 }
25
26
2.加载编辑列和删除列按钮的方法如下:



1public void LoadEditColumn()
2 {
3 EditCommandColumn ecc = new EditCommandColumn();//更新按钮列
4 ecc.SortExpression = "desc";
5 ecc.ButtonType = ButtonColumnType.LinkButton;//链接按钮
6 ecc.EditText = "编辑";
7 ecc.UpdateText = "更新";
8 ecc.CancelText = "取消";
9 ecc.ItemStyle.Width = 70;
10 this.Columns.AddAt(0, ecc);//增加按钮列
11 }
12
13 public void LoadDeleteColumn()
14 {
15 ButtonColumn bc = new ButtonColumn();
16 bc.SortExpression = "desc";
17 bc.CommandName = "Delete";
18 bc.Text = "删除";
19 bc.ItemStyle.Width = 70;
20 this.Columns.AddAt(1, bc);//增加按钮列
21 }
22
23
3.在点击编辑,取消和跳转指定分页上也进行了封装如下:


1 public void EditByItemIndex(int itemindex)
2 {
3 this.EditItemIndex = itemindex;
4 BindData();
5 }
6
7 public void Cancel()
8 {
9 this.EditItemIndex = -1;
10 BindData();
11 }
12
13 public void LoadCurrentPageIndex(int value)
14 {
15 this.CurrentPageIndex = (value < 0) ? 0 : value;
16 BindData();
17 }
18
19
4.点击表头的排序任务通过下面的属性来完成:



1private string sort;
2
3 [Bindable(true), Category("Appearance"), DefaultValue("")]
4 public string Sort
5 {
6 get
7 {
8 return sort;
9 }
10 set
11 {
12 sort = value;
13 SortTable(sort, (DataTable)null);
14 }
15 }
16
17

而SortTable函数的声明如下:



1public void SortTable(string SortExpression, DataTable dt)
2 {
3 DataView dv = new DataView();
4 if (dt != null && dt.Rows.Count > 0)
5 {
6 dv = new DataView(dt);
7 }
8 else
9 {
10 if (this.SqlText != null && this.SqlText != "")
11 {
12 dv = new DataView(DbHelper.ExecuteDataset(CommandType.Text, this.SqlText).
13 Tables[0]);
14 }
15 else
16 {
17 return;
18 }
19 }
20 dv.Sort = SortExpression.Replace("21 this.DataGridSortType;
22 //dv.Sort= SortExpression+" "+this.DataGridSortType;
23 this.DataSource = dv;
24 this.DataBind();
25 }
26
27
28 public void SortTable(string SortExpression, string sqlstring)
29 {
30 DataView dv = new DataView();
31 if (sqlstring != null && sqlstring != "")
32 {
33 dv = new DataView(DbHelper.ExecuteDataset(CommandType.Text, sqlstring).
34 Tables[0]);
35 }
36 else
37 {
38 return;
39 }
40
41 dv.Sort = SortExpression.Replace("42 this.DataGridSortType;
43 this.DataSource = dv;
44 this.DataBind();
45 }
46
47
而里面的DataGridSortType属性, 即标识当前是升序还是降序排列当前表字段:



1 [Description("表头的名称。"), Category("Appearance"), DefaultValue("ASC")]
2 public string DataGridSortType
3 {
4 get
5 {
6
7 object obj = ViewState["DataGridSortType"];
8 string ascordesc = obj == null ? "ASC" : (string)obj;
9 if (ascordesc == "ASC")
10 {
11 ViewState["DataGridSortType"] = "DESC";
12 return "DESC";
13 }
14 else
15 {
16 ViewState["DataGridSortType"] = "ASC";
17 return "ASC";
18 }
19
20 }
21 set
22 {
23 ViewState["DataGridSortType"] = value;
24 }
25 }
26
27
5.当按表头某字段进行排序时,在字段名称后添加“向下”或“向上”箭头icon。这里为了实现和使用方便,在
继承自datagrid的基础上绑定(详见构造函数)并实现了SortGrid方法(下面代码比较简单,就不做说明了):



1protected void SortGrid(Object sender, DataGridSortCommandEventArgs e)
2 {
3
4 SortTable(e.SortExpression, (DataTable)null);
5
6 foreach (System.Web.UI.WebControls.DataGridColumn dc in this.Columns)
7 {
8 if (dc.SortExpression == e.SortExpression)
9 {
10 if (dc.HeaderText.IndexOf("13 {
14 dc.HeaderText = dc.HeaderText.Replace("15 gif height=13>", "");
16 }
17 else
18 {
19 dc.HeaderText = dc.HeaderText.Replace("20 gif height=13>", "");
21 }
22 }
23 else
24 {
25 if (this.DataGridSortType == "ASC")
26 {
27 dc.HeaderText = dc.HeaderText + "28 height=13>";
29 }
30 else
31 {
32 dc.HeaderText = dc.HeaderText + "33 height=13>";
34 }
35 }
36 }
37 else
38 {
39 dc.HeaderText = dc.HeaderText.Replace("40 }
41 }
42 }
43
44
45
6.当鼠标在数据行间移动时的背景颜色变化的效果也设置在了控件中,相应的代码段如下:



1 public void DataGrid_ItemDataBound(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
2 {
3 if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
4 {
5 e.Item.Attributes.Add("onmouseover", "this.className='mouseoverstyle'");
6 e.Item.Attributes.Add("onmouseout", "this.className='mouseoutstyle'");
7 e.Item.Style["cursor"] = "hand";
8 }
9
10

通过上面的一番"折腾",使用原来很好用的datagrid在使用上进一步“代码瘦身”,相应的CS代码也相应的变成了
下面的样子(数据表通过运行下载包中的SQL脚本创建即可):



1protected void Page_Load(object sender, EventArgs e)
2 {
3 if (!Page.IsPostBack)
4 {
5 BindData();
6 }
7 }
8
9 public void BindData()
10 {
11 //是否允许自定义分页(继承自.net datagrid)
12 DataGrid1.AllowCustomPaging = false;
13 //定义列表名称
14 DataGrid1.TableHeaderName = "过滤词列表";
15 DataGrid1.BindData("SELECT * FROM [dnt_smilies]");
16 }
17
18 protected void Sort_Grid(Object sender, DataGridSortCommandEventArgs e)
19 {
20 DataGrid1.Sort = e.SortExpression.ToString();
21 }
22
23
24 protected void DataGrid_PageIndexChanged(object source, DataGridPageChangedEventArgs e)
25 {
26 DataGrid1.LoadCurrentPageIndex(e.NewPageIndex);
27 }
28
29 protected void DataGrid_Edit(Object sender, DataGridCommandEventArgs E)
30 {
31 DataGrid1.EditByItemIndex(E.Item.ItemIndex);
32 }
33
34 protected void DataGrid_Cancel(Object sender, DataGridCommandEventArgs E)
35 {
36 DataGrid1.Cancel();
37 }
38
39


当然,如果您觉得还是以前的.net datagrid 使用方便,这个控件也是兼容的。


上面的改进只是为了少写代码,是一种“偷懒”的行径。而下面的代码就是在microsoft datagrid基础上的订制
改进了。



1.因为分样的方式要与论坛前台的"分页样式"相类似,所以要在分页页码位置之后添加诸如: 当前页码,总页数,
总记录数,跳转到指定页面文本框等,所以下面的代码被开发出来。



1public void DataGrid_ItemCreated(Object sender, DataGridItemEventArgs e)
2 {
3 ListItemType elemType = e.Item.ItemType;
4
5 if (elemType == ListItemType.Pager)
6 {
7 TableCell cell1 = (TableCell)e.Item.Controls[0];
8 cell1.HorizontalAlign = HorizontalAlign.Left;
9 cell1.VerticalAlign = VerticalAlign.Bottom;
10 cell1.CssClass = "datagridPager";
11
12 LiteralControl splittable = new LiteralControl("splittable");
13 splittable.Text = "

14
";
15 cell1.Controls.AddAt(0, splittable);
16
17 LiteralControl PageNumber = new LiteralControl("PageNumber");
18 PageNumber.Text = " ";
19 if (this.PageCount <= 1)
20 {
21 try
22 {
23 cell1.Controls.RemoveAt(1); //当页数为1时, 则不显示页码
24 }
25 catch { ; }
26 }
27 else
28 {
29 PageNumber.Text = "&nbsp;&nbsp;";
30 }
31 PageNumber.Text += "共 " + this.PageCount + " 页, 当前第 " +
32 (this.CurrentPageIndex + 1) + " 页";
33
34 if (this.VirtualItemCount > 0)
35 {
36 PageNumber.Text += ", 共 " + this.VirtualItemCount + " 条记录";
37 }
38
39
40 PageNumber.Text += " &nbsp;&nbsp;" + ((this.PageCount > 1) ? "跳转到:" : "");
41 cell1.Controls.Add(PageNumber);
42
43
44 //当大于1时显示跳转按钮
45 if (this.PageCount > 1)
46 {
47 //加载跳转文件框
48 GoToPagerInputText.ID = "GoToPagerInputText";
49 GoToPagerInputText.Attributes.Add("runat", "server");
50 GoToPagerInputText.Attributes.Add("onkeydown", "if(event.keyCode==13)
51 {
52 var gotoPageID=this.name.replace('InputText','Button');
53 return(document.getElementById(gotoPageID)).focus();}
54 ");
55
56 GoToPagerInputText.Size = 6;
57 GoToPagerInputText.Value = (this.CurrentPageIndex == 0) ? "1" :
58 (this.CurrentPageIndex + 1).ToString();
59 cell1.Controls.Add(GoToPagerInputText);
60
61 PageNumber = new LiteralControl("PageNumber");
62 PageNumber.Text = "页&nbsp;&nbsp;";
63 cell1.Controls.Add(PageNumber);
64
65 //加载跳转按钮
66 GoToPagerButton.ID = "GoToPagerButton";
67 GoToPagerButton.Text = " Go ";
68 cell1.Controls.Add(GoToPagerButton);
69 }
70
71 e.Item.Controls.Add(cell1);
72
73
2. 相信用过.net datagrid 的用户对下面代码的用法会比较熟悉:
(控件名).PagerStyle.Mode=PagerMode.NumericPages;


其实在一开始使用这种分类样式时,还觉得不错,但时间一长,数据一多起来就会在“上一页”和“下一页”
的显示位置上出现"..."这样的链接,我问过许多用户,他们中不少人一开始都搞不清“...”都底是什么东西。于
是我就想把这个表示“上一页”或“下一页”的符号用真正的汉字进行替换。所以就在这个控件中出现了下面的代
码段了(接上面代码段):


1
2 //上面的代码段
3 TableCell pager = (TableCell)e.Item.Controls[0];
4
5 for (int i = 1; i < pager.Controls.Count; i += 2)
6 {
7 Object o = pager.Controls[i];
8
9 if (o is LinkButton)
10 {
11 LinkButton h = (LinkButton)o;
12 if (h.Text == "" && i == 1)//pager.Controls[i].ID == "_ctl0")
13 {
14 h.Text = "上一页";
15 continue;
16 }
17 if (i > 1 && h.Text == "")
18 {
19 h.Text = "下一页";
20 continue;
21 }
22
23 //下面JS用于当跳转页面时显示“正在加载数据”层。
24 h.Attributes.Add("onclick", "javascript:document.getElementById('Layer5').innerHTML
25 ='

26 />
正在加载数据


27

';document.getElementById('success').style.display ='block';");
28 }
29 if (o is Label)
30 {
31 Label l = (Label)o;
32 if (l.Text == "" && i == 1)//l.ID == "_ctl0")
33 {
34 l.Text = "上一页";
35 }
36
37 if (i > 1 && l.Text == "")
38 {
39 l.Text = "下一页";
40 }
41 }
42 }
43
44
45

3.为了减少因为使用控件而生成过多冗长的viewstate代码,添加了如下的属性:


1[Bindable(true), Category("Appearance"), DefaultValue("")]
2 public bool SaveDSViewState
3 {
4 get
5 {
6 object obj = ViewState["SaveDSViewState"];
7 if (obj == null) return false;
8 else
9 {
10 if (obj.ToString().ToLower() == "true")
11 return true;
12 else
13 return false;
14 }
15 }
16 set
17 {
18 ViewState["SaveDSViewState"] = value;
19 }
20 }
21
通过上面的属性设置来判断是否EnableViewState,如下:


1if (!this.SaveDSViewState)
2 {
3 this.Controls[0].EnableViewState = false;
4 }
5

4.为了让多行编辑记录并提交更方便,还添加了IsFixConlumnControls属性,当它的值为TRUE时,则当前分页下的
所有记录都以文本框的形式进行显示,也就是在文章一开始的效果图2 中显示的效果(里面的下拉列表框和复选框除外)。
而相应实现代码如下所示:



1 public void DataGrid_ItemDataBound(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
2 {
3
4
5 if (this.IsFixConlumnControls)
6 {
7 if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
8 {
9 for (int i = 0; i < e.Item.Cells.Count; i++)
10 {
11 if ((!e.Item.Cells[i].HasControls()))
12 {
13 //判断是否存在只读属性
14 if (GetBoundColumnFieldReadOnly()[i].ToString().ToLower() == "false")
15 {
16 Discuz.Control.TextBox t = new Discuz.Control.TextBox();
17 t.ID = GetBoundColumnField()[i].ToString();
18 t.Text = e.Item.Cells[i].Text.Trim().Replace("&nbsp;", "");
19
20 //设置宽度
21 if (this.Columns[i].ItemStyle.Width.Value > 0)
22 {
23 t.Width = (int)this.Columns[i].ItemStyle.Width.Value;
24 }
25 else
26 {
27 t.Width = 100;
28 }
29
30 e.Item.Cells[i].Controls.Add(t);
31 }
32
33 }
34 else
35 {
36 foreach (System.Web.UI.Control c in e.Item.Cells[i].Controls)
37 {
38 //加载discuz!nt下拉列表框控件
39 if (c is Discuz.Control.DropDownList)
40 {
41 Discuz.Control.DropDownList __dropdownlist = (Discuz.Control.DropDownList)c;
42 if (__dropdownlist.SqlText != "")
43 {
44 __dropdownlist.AddTableData(__dropdownlist.SqlText);
45 }
46
47 try
48 {
49 __dropdownlist.SelectedValue = Convert.ToString(DataBinder.Eval(e.Item.
50 DataItem, __dropdownlist.DataValueField));
51 }
52 catch
53 { ;}
54 }
55
56 //加载普通下拉控件
57 if (c is System.Web.UI.WebControls.DropDownList)
58 {
59 System.Web.UI.WebControls.DropDownList __dropdownlist = (System.Web.UI.
60 WebControls.DropDownList)c;
61 try
62 {
63 __dropdownlist.SelectedValue = Convert.ToString(DataBinder.Eval(e.Item.
64 DataItem, __dropdownlist.DataValueField));
65 }
66 catch
67 { ;}
68 }
69
70 }
71 }
72
73
74
75
同时为便于得到指定行的控件的属性值,还添加了下面两个方法:


1//得到指定行的控件字段的值
2 public string GetControlValue(int controlnumber, string fieldname)
3 {
4 return DNTRequest.GetFormString(this.ClientID.Replace("_", ":") + ":_ctl" + (controlnumber + 3) +
5 ":" + fieldname);
6 }
7



1//得到指定行的CheckBox控件字段的值
2 public bool GetCheckBoxValue(int controlnumber, string fieldname)
3 {
4 string selectcontrolvalue = GetControlValue(controlnumber, fieldname);
5 if (selectcontrolvalue == "on")
6 {
7 return true;
8 }
9 else
10 {
11 return false;
12 }
13 }
14

当然为了设置和使用的方便和提高开发效率,还有一些属性和方法要么被重写(如DataSource等),要么被添加了进来
(如TableHeaderName等)。大家可以详细看一下包中的源码即可, 这里就不再多说了:)


说句心里话:


对于这个控件,从公司产品开发的角度来说,基本上满足需要了:)


但从我个人角度来看却不那么让人满意,原因就是看到了Component Art 里面的Datagrid源码(当然它里面的其它控
件也同样优秀),让我感到“无地自容”。甚至相当长的一段时间里我都不想(或者说不敢)再写任何东西,因为写出来的代码和功能跟人家的东西一对比,就感到自己写的就是“垃圾”。这段时间大约持约了一个多月。相信园子里的朋友中有些人会有类以的经历吧!


但过后慢慢自信心就恢复了过来,因为如果放弃不写代码,水平就会停止下来,而以前所积攒的问题也永远得不到解决,所以还是逆着头皮“上路”了。现在回过头来看,一年前的这种心态真是很害人,我甚至想起以前温瑞安的一本武侠小说时中的人物,那位大侠自出师以来就是每战必败,江湖人称“逢打必败”冯无极(具体名字记不清了)。人家在那种情况下居然都能无所谓,而自己这些年来自认成熟了不少,但还有这种心理,现在回想起来实在是可笑。



好了,主要是东西就先交待到这里了。如果大家有什么问题或建议,欢迎与我交流。
我的邮件是daizhj@discuz.com, daizhj617595@126.com

下载链接:/Files/daizhj/datagrid_Controls_Test.rar


来源:cnblogs







添加到del.icio.us 添加到新浪ViVi 添加到百度搜藏 添加到POCO网摘 添加到天天网摘365Key 添加到和讯网摘 添加到天极网摘 添加到黑米书签 添加到QQ书签 添加到雅虎收藏 添加到奇客发现 diigo it 添加到饭否 添加到飞豆订阅 添加到抓虾收藏 添加到鲜果订阅 digg it 貼到funP 添加到有道阅读 Live Favorites 添加到Newsvine 打印本页 用Email发送本页 在Facebook上分享


Disclaimer Privacy Policy About us Site Map

If you have any requirements, please contact webmaster。(如果有什么要求,请联系站长)
Copyright ©2011-
uuhomepage.com, Inc. All rights reserved.