首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 發現之旅:高效能 ASP.NET TreeView 控制項開發 (上)——從問題分析到架構設計

     編輯:關於C#

前言:效能瓶頸的根因分析

專案中採用的 dtree JavaScript 樹狀元件載入緩慢,經分析發現其核心流程為:

C# 查詢 DB → 拼接 JavaScript 字串 → 傳輸至瀏覽器 → JS 解析執行 → 字串拼接生成 HTML → document.write/innerHTML 填充

三大瓶頸:

  1. JavaScript 字串拼接極慢:解釋執行、無 StringBuilder、大量中間物件
  2. 傳輸體積大:JS 代碼包含邏輯與資料,數千節點輕鬆超過百 KB
  3. 瀏覽器解析負擔重:eval/Function 建構函數、DOM 操作頻繁

資料庫查詢、C# 執行、區域網路傳輸均非瓶頸。

解決方案演進:三種架構對比

方案一:伺服器端 C# 直接生成 HTML

C# 查詢 DB → StringBuilder 生成 HTML → 傳輸 HTML → 瀏覽器直接渲染
  • ✅ C# 編譯執行快、有 StringBuilder
  • ❌ HTML 體積龐大 (含大量重複標籤/樣式),頻寬壓力大
  • ❌ 伺服器 CPU 佔用高,難以水平擴展

方案二:COM 元件加速 (MSXML + XSLT)

C# 查詢 DB → 生成 XML → 傳輸 XML + JS → 瀏覽器呼叫 MSXML COM → XSLT 轉換 → HTML
  • ✅ MSXML 為 C++ 實作,XSLT 轉換極快
  • ✅ XML 體積小,僅含純資料
  • ✅ XSLT 為標準語言,伺服器/客戶端通用
  • ⚠️ 需部署 COM 元件,相容性維護成本高

方案三:原生 IE XML Data Island + XSLT (最終採用)

C# 查詢 DB → XML 序列化 → 傳輸 XML → 瀏覽器內建 MSXML → XSLT 轉換 → HTML
  • ✅ 無額外部署,IE 內建 MSXML 4.0+
  • ✅ XML Data Island 將 XML/XSLT 嵌入 HTML,單檔部署
  • ✅ 支援伺服器端/客戶端雙模式 XSLT
  • ✅ 支援動態載入子節點 (XMLSource 機制)

目標 HTML 結構設計:Table 巢狀結構

每個節點佔一 <tr>,兩欄:

  • 第一欄 (16px):連接線背景圖 + 展開/收合圖示 (id=NodeID_expend)
  • 第二欄:節點圖示 (id=NodeID_icon) + 文字連結 (id=NodeID_text) + 子節點 <table id=NodeID_table>

HTML 結構示意圖

範例 HTML 片段

<table cellspacing="0" cellpadding="0" border="1" bordercolor="black" width="187">
  <tr>
    <td valign="top" align="left" width="16" background="SkyTreeViewControl_line.gif" height="16">
      <img id="NodeID_expend" src="SkyTreeViewControl_expend.gif">
    </td>
    <td valign="top">
      <img id="NodeID_icon" height="16" src="SkyTreeViewControl_open.bmp">
      <a id="NodeID_text">10359 成先生</a>
      <table id="NodeID_table" cellspacing="0" cellpadding="0" border="1" bordercolor="black">
        <tr><td width="16"><img src="SkyTreeViewControl_child.gif"></td>
            <td><img id="IDAIL4QC_icon" src="SkyTreeViewControl_default.bmp"><a id="IDAIL4QC_text">餅乾</a></td></tr>
        <tr><td width="16"><img src="SkyTreeViewControl_child.gif"></td>
            <td><img id="IDARL4QC_icon" src="SkyTreeViewControl_default.bmp"><a id="IDARL4QC_text">花奶酪</a></td></tr>
        <tr><td width="16"><img src="SkyTreeViewControl_lastchild.gif"></td>
            <td><img id="IDAWL4QC_icon" src="SkyTreeViewControl_default.bmp"><a id="IDAWL4QC_text">溫馨奶酪</a></td></tr>
      </table>
    </td>
  </tr>
</table>

JavaScript 互動設計

功能實作方式關鍵 API
展開/收合切換 table.style.display ('none'/'')element.style.display
圖示切換交換 src 與自訂 SrcBack 屬性getAttribute/setAttribute
高亮選中切換 className (TreeNode/SelectedNode)element.className
動態載入讀取 XMLSource → 設定 XML Data Island srcxmlIsland.src

標準化 DOM API 選擇

刻意使用 getAttribute/setAttribute 而非 element.SrcBack,確保符合 W3C DOM 標準,理論上支援非 IE 瀏覽器 (需替換 XML Data Island 為 XMLHttpRequest)。

XML Data Island 技術詳解

<xml id="XMLIslandID">
  <METADATA>
    <AUTHOR>John Smith</AUTHOR>
    <GENERATOR>Visual Notepad</GENERATOR>
  </METADATA>
</xml>
  • IE 專屬擴展,可內嵌 XML 或透過 src 載入外部 XML
  • JS 存取:xmlIsland.XMLDocument 取得 DOMDocument
  • 事件:onreadystatechange 監聽載入狀態
  • 優勢:減少外部檔案依賴,單一 HTML 檔即可完整運行

節點 XML 結構設計

<?xml version="1.0" encoding="utf-8"?>
<RootNodes>
  <Node>
    <Icon>customer.bmp</Icon>
    <Text>艾德高科技</Text>
    <Nodes>
      <Node>
        <Icon>order.bmp</Icon>
        <Text>10359 成先生</Text>
        <Nodes>
          <Node>
            <Icon>product.bmp</Icon>
            <Text>餅乾</Text>
            <OnClick>alert('餅乾')</OnClick>
            <Nodes/>
          </Node>
        </Nodes>
      </Node>
    </Nodes>
  </Node>
</RootNodes>

元素定義:Icon 圖示、Text 文字、OnClick 點擊腳本、Link 超連結、XMLSource 動態載入 URL、Nodes 子節點容器。

XSLT 模板架構

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="https://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="html" indent="no"/>
  
  <!-- 主模板:轉換入口 -->
  <xsl:template match="/*"> ... </xsl:template>
  
  <!-- 遞迴節點模板 -->
  <xsl:template name="TreeNode"> ... </xsl:template>
</xsl:stylesheet>
  • xsl:output method="html" indent="no":輸出精簡 HTML
  • 主模板匹配根元素,建立根 <table>,對每個 Node 呼叫 TreeNode 模板
  • TreeNode 模板接受 Level 參數,遞迴生成巢狀結構

專案檔案結構

檔案用途
Default.aspx示範頁面,雙 TreeView 對比
SkyTreeNode.cs節點實體類別,可 XML 序列化
SkyTreeNodeList.cs強型別節點集合
TreeViewNodeXml.aspx動態 XML 供應端點
SkyTreeViewControl.bmp工具箱圖示
SkyTreeViewControl.cs控制項核心邏輯
SkyTreeViewControl.xsltXSLT 模板 (嵌入資源)
SkyTreeViewControl_*.gif/bmp樹狀結構圖示

SkyTreeNode 關鍵屬性與序列化屬性

[Serializable]
[XmlType("Node")]
public class SkyTreeNode
{
    public string ID { get; set; }           // 節點唯一 ID,建議 Guid.NewGuid()
    public string Text { get; set; }         // 顯示文字
    public string Icon { get; set; }         // 圖示 URL
    public string Link { get; set; }         // 超連結
    public string OnClick { get; set; }      // 點擊 JS 代碼
    public string XMLSource { get; set; }    // 動態載入 URL
    
    [XmlIgnore]  // 避免循環引用
    public SkyTreeNode Parent { get; set; }
    
    [XmlArrayItem("Node", typeof(SkyTreeNode))]
    public SkyTreeNodeList Nodes { get; } = new SkyTreeNodeList(this);
}

SkyTreeNodeList:強型別集合

[Serializable]
public class SkyTreeNodeList : CollectionBase
{
    private SkyTreeNode _owner;
    public SkyTreeNodeList(SkyTreeNode owner = null) { _owner = owner; }
    
    public SkyTreeNode this[int index] => (SkyTreeNode)List[index];
    
    public int Add(SkyTreeNode node)
    {
        if (node == null) throw new ArgumentNullException(nameof(node));
        if (_owner != null) node.Parent = _owner;
        return List.Add(node);
    }
    // AddRange, Remove, IndexOf, Contains ...
}

控制項核心屬性

屬性類型說明
AutoScrollbool自動顯示捲軸
GenerateAtServerbooltrue=伺服器端 XSLT,false=客戶端 XSLT
DynamicLoadChildNodesbool啟用 XMLSource 動態載入
IndentXMLboolXML 輸出縮排 (除錯用)
TreeNodeStyleStringstring節點 CSS 樣式
SelectedNodeStyleStringstring選中節點 CSS 樣式

OnLoad:CSS 樣式註冊策略

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    string css = $".SkyTreeViewControl_TreeNode {{{TreeNodeStyleString}}} " +
                 $".SkyTreeViewControl_SelectedNode {{{SelectedNodeStyleString}}}";

    if (Page.Header != null)  // ASP.NET 2.0+ <head runat=server>
    {
        if (!Page.Header.Controls.Cast().Any(c => c.ID == "SkyTreeViewControl_Style"))
        {
            var style = new HtmlGenericControl("style") { ID = "SkyTreeViewControl_Style", InnerHtml = css };
            Page.Header.Controls.Add(style);
        }
    }
    else  // ASP.NET 1.x 相容
    {
        Page.ClientScript.RegisterClientScriptBlock(
            GetType(), "SkyTreeViewControl_Style", $"");
    }
}

Render/RenderContents:設計模式與執行模式分離

protected override void Render(HtmlTextWriter writer)
{
    if (AutoScroll) Style["overflow"] = "auto";
    base.Render(writer);  // 輸出 <div> 標籤 (TagKey = HtmlTextWriterTag.Div)
}

protected override void RenderContents(HtmlTextWriter writer)
{
    if (DesignMode)  // VS 設計器
    {
        writer.Write($"{ID}
Type: {GetType().FullName}
GenerateAtServer: {GenerateAtServer}..."); return; } // 真實執行:輸出三段 HTML + 節點資料 (見中篇) }

運行畫面與效能表現

示範頁面截圖

  • 左側:靜態完整樹,3072 節點,一次性載入
  • 右側:動態載入樹,初始 91 節點,按需展開載入子節點
  • 客戶端 XSLT 模式:頁面 300KB vs 伺服器端 2MB (6.7x 差距)

總結:架構設計的核心洞見

  1. 瓶頸定位精準:JS 字串拼接 → 改用 C++ 級 XSLT 引擎
  2. 資料與呈現分離:XML 傳輸純資料,XSLT 定義呈現邏輯
  3. 雙模式渲染:大數據走客戶端 (分擔 CPU),小數據走伺服器端 (簡化前端)
  4. 按需載入:XMLSource 機制實現虛擬化,首屏極速
  5. 標準化技術棧:XML/XSLT/DOM 為 W3C 標準,理論跨瀏覽器

這個 2008 年的控制項,以 XML Data Island + XSLT + JavaScript 實現了現代前端框架的核心範式:聲明式模板、資料驅動視圖、虛擬化渲染、伺服器/客戶端同構。雖然 IE 專屬技術已成歷史,但其架構思想在 React Server Components、Astro Islands、Qwik Resumability 中依然熠熠生輝。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved