TreeView 是呈現階層式資料 (選單、組織架構、分類目錄) 的經典控制項。配合 XmlDataSource 可直接以 XML 檔案為資料源,無需寫遞迴程式碼建立節點,透過 TreeNodeBinding 定義 XML 元素與樹狀節點的對應關係,實現宣告式綁定。
<?xml version="1.0" encoding="utf-8"?>
<contact name="聯絡人總覽">
<genre name="華南地區">
<person Text="負責人">
<name>張三</name>
<sex>男</sex>
<age>25</age>
<address>廣州市黃埔區</address>
</person>
<person Text="負責人">
<name>李四</name>
<sex>男</sex>
<age>28</age>
<address>佛山市南海區</address>
</person>
</genre>
<genre name="華北地區">
<person Text="負責人">
<name>王五</name>
<sex>男</sex>
<age>30</age>
<address>北京市海澱區</address>
</person>
</genre>
</contact>
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TreeViewXmlDemo.aspx.cs" Inherits="Demo.TreeViewXmlDemo" %>
<!DOCTYPE html>
<html>
<head runat="server">
<title>TreeView XML 綁定示範</title>
</head>
<body>
<form id="form1" runat="server">
<div style="padding:20px;">
<asp:XmlDataSource ID="XmlDataSource1" runat="server"
DataFile="~/App_Data/Contacts.xml"
XPath="contact/genre/person" />
<asp:TreeView ID="TreeView1" runat="server"
DataSourceID="XmlDataSource1"
ShowLines="true"
ExpandDepth="2"
NodeIndent="15">
<NodeStyle Font-Names="Microsoft JhengHei" Font-Size="10pt" />
<HoverNodeStyle ForeColor="Red" />
<SelectedNodeStyle BackColor="LightBlue" ForeColor="DarkBlue" />
</asp:TreeView>
</div>
</form>
</body>
</html>
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
TreeView1.ShowLines = true;
// 1. 根節點:contact 元素 -> 顯示 name 屬性
var contactBinding = new TreeNodeBinding
{
DataMember = "contact",
ValueField = "name",
TextField = "name",
Depth = 0
};
TreeView1.DataBindings.Add(contactBinding);
// 2. 第一層:genre 元素 -> 顯示 name 屬性
var genreBinding = new TreeNodeBinding
{
DataMember = "genre",
ValueField = "name",
TextField = "name",
Depth = 1,
PopulateOnDemand = false
};
TreeView1.DataBindings.Add(genreBinding);
// 3. 第二層:person 元素 -> 顯示 Text 屬性
var personBinding = new TreeNodeBinding
{
DataMember = "person",
ValueField = "Text",
TextField = "Text",
Depth = 2
};
TreeView1.DataBindings.Add(personBinding);
// 4. 第三層:子元素 (name, sex, age, address) -> 顯示內文 (#InnerText)
string[] leafFields = { "name", "sex", "age", "address" };
foreach (string field in leafFields)
{
var leafBinding = new TreeNodeBinding
{
DataMember = field,
ValueField = "#InnerText",
TextField = "#InnerText",
Depth = 3,
// 格式化顯示:標籤: 值
FormatString = $"{GetFieldLabel(field)}: {{0}}"
};
TreeView1.DataBindings.Add(leafBinding);
}
}
}
private string GetFieldLabel(string field) => field switch
{
"name" => "姓名",
"sex" => "性別",
"age" => "年齡",
"address" => "地址",
_ => field
};
| TreeNodeBinding 屬性 | 說明 | 本例設定 |
|---|---|---|
| DataMember | XML 元素名稱 (區分大小寫) | contact, genre, person, name, sex... |
| ValueField | 節點 Value 屬性來源 | 屬性值用 "@屬性名"、內文用 "#InnerText" |
| TextField | 節點顯示文字來源 | 同 ValueField,或使用 FormatString 格式化 |
| Depth | 綁定深度 (0 為根) | 對應 XML 階層深度 |
| FormatString | 顯示格式化字串 | "姓名: {0}" 等 |
| PopulateOnDemand | 是否延遲載入子節點 | 大量資料時設 true 提升效能 |
// 僅顯示「華南地區」下的負責人
XmlDataSource1.XPath = "contact/genre[@name='華南地區']/person";
protected void BtnAddPerson_Click(object sender, EventArgs e)
{
string xmlPath = Server.MapPath("~/App_Data/Contacts.xml");
XDocument doc = XDocument.Load(xmlPath);
// 找到第一個 genre 新增 person
var firstGenre = doc.Root.Element("genre");
firstGenre.Add(new XElement("person", new XAttribute("Text", "新負責人"),
new XElement("name", "趙六"),
new XElement("sex", "女"),
new XElement("age", "26"),
new XElement("address", "深圳市南山區")));
doc.Save(xmlPath);
// 重新綁定
TreeView1.DataBind();
}
protected void TreeView1_SelectedNodeChanged(object sender, EventArgs e)
{
string value = TreeView1.SelectedNode.Value;
string text = TreeView1.SelectedNode.Text;
int depth = TreeView1.SelectedNode.Depth;
// 根據深度判斷節點類型
string type = depth switch
{
0 => "總覽",
1 => "地區",
2 => "負責人",
3 => "明細欄位",
_ => "未知"
};
LblInfo.Text = $"類型: {type}, 值: {value}, 文字: {text}";
}
PopulateOnDemand="true",在 TreeNodePopulate 事件中動態載入子節點XmlDataSource.EnableCaching="true" CacheDuration="300" (5 分鐘)EnableViewState="false" 若無需回傳後保持展開狀態
呈現三層結構:聯絡人總覽 → 地區 → 負責人 → 明細欄位,節點連線清晰,支援展開/摺疊互動。