我們在開發的時候一定遇到,使用datagrid的時候由于不想分頁(數據沒有那么多)但是又顯示不在一頁里面,此時我們希望在datagrid里面出現一個滾動條,可以上下滾動datagrid里面的數據而不用上下滾動頁面,由于寫本文的目的是為了說明如何實現,所以對于細節性的問題讀者可以自己思考完成(比如:既要分頁又要滾動等等)。為了可以滾動datagrid我們需要一個可以讓客戶端的table滾動js腳本(該js代碼我是從codeproject上面下載的),但又不能滾動table的題頭(也就是第一行)。我們都知道datagrid在解釋到客戶端以后將會生成一個table,但是這個table是由<tr><td>組成的,我們的腳本里面是需要使用到table的thead和tbody的(在大多數的客戶端的應用中都要用到此功能比如:客戶端的排序、以及列的托拽等等),因此我們接下來的任務就是如何為我們客戶端的這個datagrid添加<thead><tbody>了。如果你對用戶的自定義控件以及asp.net頁面的原理有所了解,我們知道控件最后都是要呈現(render)在頁面上的,因此我們可以重寫這個方法來完成datagrid的自定義呈現。聽一聽真的有些嚇人,那么復雜的控件怎么呈現?不要著急,首先我們創建一個自定義控件如下所示:
public class powerdatagrid : system.web.ui.webcontrols.datagrid 
 由此可以看出我們的控件是繼承于datagrid的,所以我們現在的這個控件在不用寫一行代碼的情況下我們的這個控件已經具有datagrid的所有的功能。接下來我們要將我們準備的js代碼內嵌到我們的控件里,好讓放這個控件的頁面上最終在客戶端都會有這段js代碼用來完成我們滾動的任務。為了完成這個工作我們要重寫預呈現的方法:
 protected override void onprerender(system.eventargs e) {
 base.onprerender(e);
 
 resourcemanager manager = new resourcemanager( this.gettype() );
 resourceset resources = manager.getresourceset(system.globalization.cultureinfo.currentculture, true, true);
 if( !page.isclientscriptblockregistered( "skysword.webcontrol.powerdatagrid library" ) ) {
 string script = resources.getstring("scrolltable");
 this.page.registerclientscriptblock("skysword.webcontrol.powerdatagrid library", script );
 this.page.registerstartupscript("skysword.webcontrols.powerdatagrid init", "<script>makescrollabletable
('"+this.id+"',true,'auto');</script>" );
 }
 }
 在該方法中我們訪問了資源文件。哦!忘了說我們還要建立一個資源文件,用來保存我們的js代碼。我們首先將資源代碼中對應scrolltable的數據(一段js腳本)注冊到客戶端的腳本塊里。最后我們為了可以初始化,將<script>makescrollabletable('"+this.id+"',true,'auto');</script>段腳本注冊到頁面加載時開始執行(我想就應該和body里面onload的方法一樣吧)。當你需要加載客戶端腳本的時候使用該方法是個不錯的選擇。好了,客戶端腳本也有了,剩下的就是處理我們的客戶端datagrid了(也就是datagrid呈現的客戶端table)。為了可以呈現我們自己的datagrid我們需要重寫呈現方法如下所示:
protected override void render(htmltextwriter output)
 {
 output.write(this.parsemarkup());
 }
 其中調用了一個parsemarkup的函數,改函數將產生一個輸出的腳本(字符串),該腳本就是一個包含thead和tbody的table。由于此方法只是由該控件自己使用所以我們將它設置成私有的代碼如下:
 private string parsemarkup(){
 // 插入thead標簽和tbody標簽
 stringwriter writer = new stringwriter();
 htmltextwriter buffer = new htmltextwriter(writer);
 base.render(buffer);
 string pmarkup = writer.tostring();
 // 找到第一個table標簽的結尾也就是第一個>字符
 pmarkup = pmarkup.insert(pmarkup.indexof(">") + ">".length, "<thead>");
 // 將第一個tr閉區間用thead包起來,現在第一個<thead>已經畫出來了需要畫
 // 它的結尾</thead>和</tbody>,同樣找到第一個</tr>來插入</thead>和</tdoby>
 pmarkup = pmarkup.insert( pmarkup.indexof("</tr>") + "</tr>".length,"</thead><tbody>");
 // 在最后一個</table>的前面插入一個</tbody>就可以了。
 pmarkup = pmarkup.replace("</table>", "</tbody></table>");
 return pmarkup; 
 }
 在這個方法中我們首先實例化了一個stringwriter的對象writer,又用該對象為參數實例了一個htmltextwriter對象buffer,最關鍵的是我們調用了基類的render用來將buffer里面填滿要輸出的東西(一堆腳本就是table,如果你是用監視器查看里面的內容就可以看到)。好了剩下的工作就是分析這個腳本了,然后我們在該腳本第一個出現<tr>的地方將這個<tr>替換成<thead>和<tr>后面的替換方法類似。最后我們將這個被我們替換和修改的table輸出到客戶端,一切ok!
注意:用到stringwriter的原因就是它可以從buffer里面保存原始的字符比如:/t/n什么的。 資源文件的配置方法:首先給你的工程添加一個資源文件,名字和你的控件一樣,然后在該文件中添加一下小節
 <data name="scrolltable">
 <value><![cdata[
 <script language = 'javascript'>
 
 var container = new array();
var onresizehandler;
function scrollbarwidth(){
 var w;
 if (! document.body.currentstyle) document.body.currentstyle = document.body.style;
 if (document.body.currentstyle.overflowy == 'visible' || document.body.currentstyle.overflowy == 'scroll'){
 w = document.body.offsetwidth - document.body.clientleft - document.body.clientwidth;
 }else{
 win = window.open("about:blank", "_blank", "top=0,left=0,width=100,height=100,scrollbars=yes");
 win.document.writeln('scrollbar');
 w = win.document.body.offsetwidth - win.document.body.clientleft - win.document.body.clientwidth;
 win.close();
 }
 return w;
}
function getactualwidth(e){
 if (! e.currentstyle) e.currentstyle = e.style;
 return e.clientwidth - parseint(e.currentstyle.paddingleft) - parseint(e.currentstyle.paddingright);
}
function findrowwidth(r){
 for (var i=0; i < r.length; i++){
 r[i].actualwidth = getactualwidth(r[i]);
 }
}
function setrowwidth(r){
 for (var i=0; i < r.length; i++){
 r[i].width = r[i].actualwidth;
 r[i].innerhtml = '<span style="width:' + r[i].actualwidth + ';">' + r[i].innerhtml + '</span>';
 }
}
function fixtablewidth(tbl){
 for (var i=0; i < tbl.thead.rows.length; i++) findrowwidth(tbl.thead.rows[i].cells);
 findrowwidth(tbl.tbodies[0].rows[0].cells);
 if (tbl.tfoot) for (var i=0; i < tbl.tfoot.rows.length; i++) findrowwidth(tbl.tfoot.rows[i].cells);
 //tbl.width = '';
 for (var i=0; i < tbl.thead.rows.length; i++) setrowwidth(tbl.thead.rows[i].cells);
 setrowwidth(tbl.tbodies[0].rows[0].cells);
 if (tbl.tfoot) for (var i=0; i < tbl.tfoot.rows.length; i++) setrowwidth(tbl.tfoot.rows[i].cells);
}
function makescrollabletable(tbl,scrollfooter,height){
 var c, pnode, hdr, ftr, wrapper, rect;
 if (typeof tbl == 'string') tbl = document.getelementbyid(tbl);
 pnode = tbl.parentnode;
 fixtablewidth(tbl);
 c = container.length;
 container[c] = document.createelement('<span style="height: 100; overflow: auto;">');
 container[c].id = tbl.id + "container";
 pnode.insertbefore(container[c], tbl);
 container[c].appendchild(tbl);
 container[c].style.width = tbl.clientwidth + 2 * tbl.clientleft + scrollbarwidth();
 hdr = tbl.clonenode(false);
 hdr.id += 'header';
 hdr.appendchild(tbl.thead.clonenode(true));
 tbl.thead.style.display = 'none';
 if (!scrollfooter || !tbl.tfoot){
 ftr = document.createelement('<span style="width:1;height:1;clip: rect(0 1 1 0);background-color:transparent;">');
 ftr.id = tbl.id + 'footer';
 ftr.style.border = tbl.style.border;
 ftr.style.width = getactualwidth(tbl) + 2 * tbl.clientleft;
 ftr.style.borderbottom = ftr.style.borderleft = ftr.style.borderright = 'none';
 }else{
 ftr = tbl.clonenode(false);
 ftr.id += 'footer';
 ftr.appendchild(tbl.tfoot.clonenode(true));
 ftr.style.bordertop = 'none';
 tbl.tfoot.style.display = 'none';
 }
 wrapper = document.createelement('<table border=0 cellspacing=0 cellpadding=0>');
 wrapper.id = tbl.id + 'wrapper';
 pnode.insertbefore(wrapper, container[c]);
 wrapper.insertrow(0).insertcell(0).appendchild(hdr);
 wrapper.insertrow(1).insertcell(0).appendchild(container[c]);
 wrapper.insertrow(2).insertcell(0).appendchild(ftr);
 wrapper.align = tbl.align;
 tbl.align = hdr.align = ftr.align = 'left';
 hdr.style.borderbottom = 'none';
 tbl.style.bordertop = tbl.style.borderbottom = 'none';
 // adjust page size
 if (c == 0 && height == 'auto'){
 onresizeadjusttable();
 onresizehandler = window.onresize;
 window.onresize = onresizeadjusttable;
 }else{
 container[c].style.height = height;
 }
}
function onresizeadjusttable(){
 if (onresizehandler) onresizehandler();
 var rect = container[0].getclientrects()(0);
 var h = document.body.clientheight - (rect.top + (document.body.scrollheight - rect.bottom));
 container[0].style.height = (h > 0) ? h : 1;
}
function printpage(){
 var tbs = document.getelementsbytagname('table');
 var e;
 for (var i=0; i < container.length; i++) container[i].style.overflow = '';
 window.print();
 for (var i=0; i < container.length; i++) container[i].style.overflow = 'auto';
}
 
 </script> 
 ]]></value>
 </data>
 
 好了,這樣就可以完成了。使用該方法可以實現客戶端的排序和托拽功能,只要你找到相應的js代碼(或者自己寫)然后使用此法分析你的客戶端代碼,最后將你的datagrid的輸出定位成你想要的結果,一切就ok了!由于時間關系該控件分頁和滾動不能同時,希望有興趣的網友可以實現之。我在寫此文章的目的旨在拋磚引玉的作用,希望對大家的編程技術有所提高和幫助。謝謝閱讀!有什么問題或者好的建議請與我聯系。
新聞熱點
疑難解答