我们在开发的时候一定遇到,使用 DataGrid 的时候由于不想分页(数据没有那么多)但是又显示不在一页里面,此时我们希望在 DataGrid 里面出现一个滚动条,可以上下滚动 DataGrid 里面的数据而不用上下滚动页面,由于写本文的目的是为了说明如何实现,所以对于细节性的问题读者可以自己思考完成(比如:既要分页又要滚动等等)。为了可以滚动 DataGrid 我们需要一个可以让客户端的 Table 滚动 js 脚本(该 js 代码我是从 CodeProject 上面下载的),但又不能滚动 Table 的题头(也就是第一行)。我们都知道 DataGrid 在解释到客户端以后将会生成一个 Table ,但是这个 Table 是由
1<tr><td> 组成的,我们的脚本里面是需要使用到 Table 的 Thead 和 Tbody 的(在大多数的客户端的应用中都要用到此功能比如:客户端的排序、以及列的托拽等等),因此我们接下来的任务就是如何为我们客户端的这个 DataGrid 添加 <thead><tbody> 了。如果你对用户的自定义控件以及 ASP.NET 页面的原理有所了解,我们知道控件最后都是要呈现 (Render) 在页面上的,因此我们可以重写这个方法来完成 DataGrid 的自定义呈现。听一听真的有些吓人,那么复杂的控件怎么呈现?不要着急,首先我们创建一个自定义控件如下所示:
2public class PowerDataGrid : System.Web.UI.WebControls.DataGrid
3由此可以看出我们的控件是继承于 DataGrid 的,所以我们现在的这个控件在不用写一行代码的情况下我们的这个控件已经具有 DataGrid 的所有的功能。接下来我们要将我们准备的 js 代码内嵌到我们的控件里,好让放这个控件的页面上最终在客户端都会有这段 js 代码用来完成我们滚动的任务。为了完成这个工作我们要重写预呈现的方法:
4protected override void OnPreRender(System.EventArgs e) {
5
6base.OnPreRender(e);
7
8ResourceManager manager = new ResourceManager( this.GetType() );
9ResourceSet resources = manager.GetResourceSet(System.Globalization.CultureInfo.CurrentCulture, true, true);
10if( !Page.IsClientScriptBlockRegistered( "SkySword.WebControl.PowerDataGrid Library" ) ) {
11String script = resources.GetString("ScrollTable");
12this.Page.RegisterClientScriptBlock("SkySword.WebControl.PowerDataGrid Library", script );
13this.Page.RegisterStartupScript("SkySword.WebControls.PowerDataGrid Init", "<script>makeScrollableTable
14
15('"+this.ID+"',true,'auto');</script>" );
16}
17}
18在该方法中我们访问了资源文件。哦!忘了说我们还要建立一个资源文件,用来保存我们的 js 代码。我们首先将资源代码中对应 ScrollTable 的数据(一段 js 脚本)注册到客户端的脚本块里。最后我们为了可以初始化,将 <script>makeScrollableTable('"+this.ID+"',true,'auto');</script> 段脚本注册到页面加载时开始执行(我想就应该和 body 里面 onload 的方法一样吧)。当你需要加载客户端脚本的时候使用该方法是个不错的选择。好了,客户端脚本也有了,剩下的就是处理我们的客户端 DataGrid 了(也就是 DataGrid 呈现的客户端 Table )。为了可以呈现我们自己的 DataGrid 我们需要重写呈现方法如下所示:
19protected override void Render(HtmlTextWriter output)
20{
21output.Write(this.parseMarkup());
22}
23其中调用了一个 parseMarkup 的函数,改函数将产生一个输出的脚本(字符串),该脚本就是一个包含 thead 和 tbody 的 Table 。由于此方法只是由该控件自己使用所以我们将它设置成私有的代码如下:
24private string parseMarkup(){
25// 插入 THead 标签和 TBody 标签
26StringWriter writer = new StringWriter();
27HtmlTextWriter buffer = new HtmlTextWriter(writer);
28base.Render(buffer);
29string pMarkup = writer.ToString();
30
31// 找到第一个 table 标签的结尾也就是第一个 > 字符
32pMarkup = pMarkup.Insert(pMarkup.IndexOf(">") + ">".Length, "<thead>");
33// 将第一个 tr 闭区间用 Thead 包起来,现在第一个 <thead> 已经画出来了需要画
34// 它的结尾 </thead> 和 </thead></tbody>, 同样找到第一个 </thead></td></tr>
来插入 和 pMarkup = pMarkup.Insert( pMarkup.IndexOf(" ") + " ".Length,"
1<tbody>");
2// 在最后一个 的前面插入一个 </tbody>
就可以了。
pMarkup = pMarkup.Replace("
", "
");
return pMarkup;
}
在这个方法中我们首先实例化了一个 StringWriter 的对象 writer ,又用该对象为参数实例了一个 HtmlTextWriter 对象 buffer ,最关键的是我们调用了基类的 Render 用来将 buffer 里面填满要输出的东西(一堆脚本就是 Table ,如果你是用监视器查看里面的内容就可以看到)。好了剩下的工作就是分析这个脚本了,然后我们在该脚本第一个出现
1<tr> 的地方将这个 <tr> 替换成 <thead> 和 <tr> 后面的替换方法类似。最后我们将这个被我们替换和修改的 Table 输出到客户端,一切 OK !
2
3注意:用到 StringWriter 的原因就是它可以从 buffer 里面保存原始的字符比如: /t/n 什么的。 资源文件的配置方法:首先给你的工程添加一个资源文件,名字和你的控件一样,然后在该文件中添加一下小节
4<data name="ScrollTable">
5<value><![CDATA[
6<script language = 'javascript'>
7
8var container = new Array();
9var onResizeHandler;
10
11function scrollbarWidth(){
12var w;
13
14if (! document.body.currentStyle) document.body.currentStyle = document.body.style;
15
16if (document.body.currentStyle.overflowY == 'visible' || document.body.currentStyle.overflowY == 'scroll'){
17w = document.body.offsetWidth - document.body.clientLeft - document.body.clientWidth;
18}else{
19win = window.open("about:blank", "_blank", "top=0,left=0,width=100,height=100,scrollbars=yes");
20win.document.writeln('scrollbar');
21w = win.document.body.offsetWidth - win.document.body.clientLeft - win.document.body.clientWidth;
22win.close();
23}
24
25return w;
26}
27
28function getActualWidth(e){
29if (! e.currentStyle) e.currentStyle = e.style;
30
31return e.clientWidth - parseInt(e.currentStyle.paddingLeft) - parseInt(e.currentStyle.paddingRight);
32}
33
34function findRowWidth(r){
35for (var i=0; i < r.length; i++){
36r[i].actualWidth = getActualWidth(r[i]);
37}
38}
39
40function setRowWidth(r){
41for (var i=0; i < r.length; i++){
42r[i].width = r[i].actualWidth;
43r[i].innerHTML = '<span style="width:' + r[i].actualWidth + ';">' + r[i].innerHTML + '</span>';
44}
45}
46
47function fixTableWidth(tbl){
48for (var i=0; i < tbl.tHead.rows.length; i++) findRowWidth(tbl.tHead.rows[i].cells);
49findRowWidth(tbl.tBodies[0].rows[0].cells);
50if (tbl.tFoot) for (var i=0; i < tbl.tFoot.rows.length; i++) findRowWidth(tbl.tFoot.rows[i].cells);
51
52//tbl.width = '';
53
54for (var i=0; i < tbl.tHead.rows.length; i++) setRowWidth(tbl.tHead.rows[i].cells);
55setRowWidth(tbl.tBodies[0].rows[0].cells);
56if (tbl.tFoot) for (var i=0; i < tbl.tFoot.rows.length; i++) setRowWidth(tbl.tFoot.rows[i].cells);
57}
58
59function makeScrollableTable(tbl,scrollFooter,height){
60var c, pNode, hdr, ftr, wrapper, rect;
61
62if (typeof tbl == 'string') tbl = document.getElementById(tbl);
63
64pNode = tbl.parentNode;
65fixTableWidth(tbl);
66
67c = container.length;
68container[c] = document.createElement('<SPAN style="height: 100; overflow: auto;">');
69container[c].id = tbl.id + "Container";
70pNode.insertBefore(container[c], tbl);
71container[c].appendChild(tbl);
72container[c].style.width = tbl.clientWidth + 2 * tbl.clientLeft + scrollbarWidth();
73
74hdr = tbl.cloneNode(false);
75hdr.id += 'Header';
76hdr.appendChild(tbl.tHead.cloneNode(true));
77tbl.tHead.style.display = 'none';
78
79if (!scrollFooter || !tbl.tFoot){
80ftr = document.createElement('<SPAN style="width:1;height:1;clip: rect(0 1 1 0);background-color:transparent;">');
81ftr.id = tbl.id + 'Footer';
82ftr.style.border = tbl.style.border;
83ftr.style.width = getActualWidth(tbl) + 2 * tbl.clientLeft;
84ftr.style.borderBottom = ftr.style.borderLeft = ftr.style.borderRight = 'none';
85}else{
86ftr = tbl.cloneNode(false);
87ftr.id += 'Footer';
88ftr.appendChild(tbl.tFoot.cloneNode(true));
89ftr.style.borderTop = 'none';
90tbl.tFoot.style.display = 'none';
91}
92
93wrapper = document.createElement('<table border=0 cellspacing=0 cellpadding=0>');
94wrapper.id = tbl.id + 'Wrapper';
95pNode.insertBefore(wrapper, container[c]);
96
97wrapper.insertRow(0).insertCell(0).appendChild(hdr);
98wrapper.insertRow(1).insertCell(0).appendChild(container[c]);
99wrapper.insertRow(2).insertCell(0).appendChild(ftr);
100
101wrapper.align = tbl.align;
102tbl.align = hdr.align = ftr.align = 'left';
103hdr.style.borderBottom = 'none';
104tbl.style.borderTop = tbl.style.borderBottom = 'none';
105
106// adjust page size
107if (c == 0 && height == 'auto'){
108onResizeAdjustTable();
109onResizeHandler = window.onresize;
110window.onresize = onResizeAdjustTable;
111}else{
112container[c].style.height = height;
113}
114}
115
116function onResizeAdjustTable(){
117if (onResizeHandler) onResizeHandler();
118
119var rect = container[0].getClientRects()(0);
120var h = document.body.clientHeight - (rect.top + (document.body.scrollHeight - rect.bottom));
121container[0].style.height = (h > 0) ? h : 1;
122}
123
124function printPage(){
125var tbs = document.getElementsByTagName('TABLE');
126var e;
127
128for (var i=0; i < container.length; i++) container[i].style.overflow = '';
129
130window.print();
131
132for (var i=0; i < container.length; i++) container[i].style.overflow = 'auto';
133}
134
135</script>
136]]></value>
137</data></tr></thead></tr></tr>