轉自:http://www.cnblogs.com/dingsea/archive/2005/10/26/262220.html相信不少人都用過微軟提供的一款控制項: IEControl,
其中的TreeView使用比較廣泛。在我參與的一個項目中,一個名為UNSPSC的模組將頻繁使用這個控制項。這個控制項在一般情況下相當好用(節點小於200個),但當節點數比較多時將使用戶端長時間等待,大資料量時會讓用戶端逾時以至於讀取失敗。本模組在進行壓力測試時,資料庫中有24000多條記錄,一次性讀取出來將使IE死掉,這自然不能適用於對UNSPSC的讀取(UNSPSC要求最多支援9000萬條記錄)。於是我想使用Ajax(Asynchronous
JavaScript and XML)的無重新整理和非同步讀取機制對其進行最佳化。
本專案檔已經上傳,在文章結尾處,大家不要再公布自己的email了,注意隱私.
對於Ajax的介紹,國內外的技術網站都有不少的資料,我在此不多說了。我所使用的Ajax來自http://ajax.schwarz-interactive.de/,大家有興趣可以去下載。
首先來看看做出來的效果:
這是剛載入好頁面的效果。
這是剛剛點擊節點,展開的瞬間(不好抓取啊)。
非同步讀取完成後,名為11000000節點的變化。這是在非同步呼叫完成後,資料已經在Tree
View中產生。
當完全展開11000000下的一個子節點時,可以發現根節點如此之多。
這是我仿造項目做的一個解決方案:
其中BorgWorX.Web.Core.Ajax產生Ajax.DLL
第一步:按AjaxGuide.doc上說的來,先在web.config中進行修改,增加:
<add
verb="POST,GET" path="ajax/*.ashx"
type="BorgWorX.Web.Core.Ajax.PageHandlerFactory, BorgWorX.Web.Core.Ajax" />
第二步:我們在page load事件時向Ajax註冊頁面類,並向tree view控制項綁定UNSPSC第一層的資料:
private void
Page_Load(object sender, System.EventArgs e)
{
BorgWorX.Web.Core.Ajax.Utility.RegisterTypeForAjax(typeof(WebForm2));
LoadNode=new TreeNode();
LoadNode.Text="Loading";
LoadNode.ID="load";
if(!IsPostBack)
{
TreeNode root=new TreeNode();
root.Text="Root";
TreeView1.Nodes.Add(root);
loadData(root,0); //Data Bind
root.Expanded=true;
}
}
第三步:在後台代碼中編寫要使用Ajax的方法,並對其添加中繼資料屬性。要注意的是這些方法必須聲明為public,在這兒我聲明一個名為returnDs的方法,它根據前置詞字元串返回資料庫中所有包含此首碼的記錄:
[BorgWorX.Web.Core.Ajax.AjaxMethod()]
public DataSet
returnDs(string PreFix)
{
int preFix=getPreFix(PreFix);
string
str="workstation id=DINGSEA;packet size=4096;user id=sa;data
source=dingsea;persist security info=False;initial catalog=GEPS";
DataSet
ds=SqlHelper.ExecuteDataset(str,"sp_loadUNSPSCCodeByLevel",preFix);
return ds;
}
private int
getPreFix(string code)
{
string tempStr;
while(code.EndsWith("00"))
{
code=code.Remove(code.Length-2,2);
}
tempStr=code;
return
tempStr.Length==0?0:Convert.ToInt32(tempStr);
}
這樣我們在用戶端寫JS的時候就可以方便的使用這個方法了。
第四步:服務端搞定後,我們來看看用戶端如何設計。通過page_load方法載入了第一層的UNSPSC
Code,也就是XX000000的所有節點並顯示出來。通過對TreeView WebControl的用戶端行為進行考察(微軟在其文章《About the
TreeView WebControl》中有提到),我們發現可以在TreeView的OnExpand事件中,進行非同步下載子層資料:
<script language="javascript">
var Index;
function ds()
{
WebForm2.returnDs(TreeView1.getTreeNode(Index).getAttribute("NodeData"),returnDs_callback);
}
function returnDs_callback(response)
{
var n=TreeView1.getTreeNode(Index);
var load=n.getChildren();
if(load.length!=1){
return;//如果已經存在資料,那就不再讀取。
}
else
{
var loadNode=load[0];
loadNode.remove();
}
var ds=response.value;
if(ds!=null && ds.Tables!=null && typeof(ds)=="object")
{
for(var i=0;i<ds.Tables[0].Rows.length;i++)
{
var newNode=TreeView1.createTreeNode();
newNode.setAttribute("NodeData",ds.Tables[0].Rows[i].UNSPSCCode);
newNode.setAttribute("Text",ds.Tables[0].Rows[i].UNSPSCCode+"
"+ds.Tables[0].Rows[i].Description);
if(newNode.getAttribute("NodeData")%100==0)
{
var loadNode=TreeView1.createTreeNode();
loadNode.setAttribute("Text","Loading......");
newNode.add(loadNode);
}
n.add(newNode);
}
}
else{alert(response.error);}
}
</script>
<script language="javascript" for="TreeView1" event="onexpand">
//TODO:在此處填寫TreeView的OnExpand事件的代碼。
Index= window.event.treeNodeIndex;//獲得展開的節點的位置,根節點為0。
if(Index=='0')return;//如果是根節點的話就直接返回。
ds();
</script>
按這樣的情況來算,業務中每層節點最多99個,一共四層節點,也就是99*99*99*99=
9227446944279201(更正:96059601,自己汗一個先。)個節點。遠遠超過需求中的9000萬個,而且在使用者展開節點後先出現的是“Loading……”的字樣,同時在伺服器上去下載節點,不但最佳化了效能提高了效率而且還更人性化、介面更有親和力。
/Files/wangyt223/project.rar
本專案檔已經上傳,在文章結尾處,大家不要再公布自己的email了,注意隱私.
對於Ajax的介紹,國內外的技術網站都有不少的資料,我在此不多說了。我所使用的Ajax來自http://ajax.schwarz-interactive.de/,大家有興趣可以去下載。
首先來看看做出來的效果:
這是剛載入好頁面的效果。
這是剛剛點擊節點,展開的瞬間(不好抓取啊)。
非同步讀取完成後,名為11000000節點的變化。這是在非同步呼叫完成後,資料已經在Tree
View中產生。
當完全展開11000000下的一個子節點時,可以發現根節點如此之多。
這是我仿造項目做的一個解決方案:
其中BorgWorX.Web.Core.Ajax產生Ajax.DLL
第一步:按AjaxGuide.doc上說的來,先在web.config中進行修改,增加:
<add
verb="POST,GET" path="ajax/*.ashx"
type="BorgWorX.Web.Core.Ajax.PageHandlerFactory, BorgWorX.Web.Core.Ajax" />
第二步:我們在page load事件時向Ajax註冊頁面類,並向tree view控制項綁定UNSPSC第一層的資料:
private void
Page_Load(object sender, System.EventArgs e)
{
BorgWorX.Web.Core.Ajax.Utility.RegisterTypeForAjax(typeof(WebForm2));
LoadNode=new TreeNode();
LoadNode.Text="Loading";
LoadNode.ID="load";
if(!IsPostBack)
{
TreeNode root=new TreeNode();
root.Text="Root";
TreeView1.Nodes.Add(root);
loadData(root,0); //Data Bind
root.Expanded=true;
}
}
第三步:在後台代碼中編寫要使用Ajax的方法,並對其添加中繼資料屬性。要注意的是這些方法必須聲明為public,在這兒我聲明一個名為returnDs的方法,它根據前置詞字元串返回資料庫中所有包含此首碼的記錄:
[BorgWorX.Web.Core.Ajax.AjaxMethod()]
public DataSet
returnDs(string PreFix)
{
int preFix=getPreFix(PreFix);
string
str="workstation id=DINGSEA;packet size=4096;user id=sa;data
source=dingsea;persist security info=False;initial catalog=GEPS";
DataSet
ds=SqlHelper.ExecuteDataset(str,"sp_loadUNSPSCCodeByLevel",preFix);
return ds;
}
private int
getPreFix(string code)
{
string tempStr;
while(code.EndsWith("00"))
{
code=code.Remove(code.Length-2,2);
}
tempStr=code;
return
tempStr.Length==0?0:Convert.ToInt32(tempStr);
}
這樣我們在用戶端寫JS的時候就可以方便的使用這個方法了。
第四步:服務端搞定後,我們來看看用戶端如何設計。通過page_load方法載入了第一層的UNSPSC
Code,也就是XX000000的所有節點並顯示出來。通過對TreeView WebControl的用戶端行為進行考察(微軟在其文章《About the
TreeView WebControl》中有提到),我們發現可以在TreeView的OnExpand事件中,進行非同步下載子層資料:
<script language="javascript">
var Index;
function ds()
{
WebForm2.returnDs(TreeView1.getTreeNode(Index).getAttribute("NodeData"),returnDs_callback);
}
function returnDs_callback(response)
{
var n=TreeView1.getTreeNode(Index);
var load=n.getChildren();
if(load.length!=1){
return;//如果已經存在資料,那就不再讀取。
}
else
{
var loadNode=load[0];
loadNode.remove();
}
var ds=response.value;
if(ds!=null && ds.Tables!=null && typeof(ds)=="object")
{
for(var i=0;i<ds.Tables[0].Rows.length;i++)
{
var newNode=TreeView1.createTreeNode();
newNode.setAttribute("NodeData",ds.Tables[0].Rows[i].UNSPSCCode);
newNode.setAttribute("Text",ds.Tables[0].Rows[i].UNSPSCCode+"
"+ds.Tables[0].Rows[i].Description);
if(newNode.getAttribute("NodeData")%100==0)
{
var loadNode=TreeView1.createTreeNode();
loadNode.setAttribute("Text","Loading......");
newNode.add(loadNode);
}
n.add(newNode);
}
}
else{alert(response.error);}
}
</script>
<script language="javascript" for="TreeView1" event="onexpand">
//TODO:在此處填寫TreeView的OnExpand事件的代碼。
Index= window.event.treeNodeIndex;//獲得展開的節點的位置,根節點為0。
if(Index=='0')return;//如果是根節點的話就直接返回。
ds();
</script>
按這樣的情況來算,業務中每層節點最多99個,一共四層節點,也就是99*99*99*99=
9227446944279201(更正:96059601,自己汗一個先。)個節點。遠遠超過需求中的9000萬個,而且在使用者展開節點後先出現的是“Loading……”的字樣,同時在伺服器上去下載節點,不但最佳化了效能提高了效率而且還更人性化、介面更有親和力。
/Files/wangyt223/project.rar