C# TreeView 控件的詳解與應(yīng)用小結(jié)
一、TreeView 控件核心概念
TreeView 是 C# WinForm/WPF 中用于以樹(shù)形層級(jí)結(jié)構(gòu)展示數(shù)據(jù)的控件,其核心組成單元有兩個(gè):
1、TreeNode(樹(shù)節(jié)點(diǎn)):TreeView 的最小展示單元,用于承載單個(gè)數(shù)據(jù)項(xiàng),支持包含文本、圖標(biāo)、自定義數(shù)據(jù)等內(nèi)容。
2、層級(jí)結(jié)構(gòu):TreeNode 支持嵌套(節(jié)點(diǎn)可以包含子節(jié)點(diǎn)),形成 “根節(jié)點(diǎn) - 子節(jié)點(diǎn) - 葉子節(jié)點(diǎn)” 的層級(jí)關(guān)系,根節(jié)點(diǎn)是樹(shù)形結(jié)構(gòu)的頂層節(jié)點(diǎn)(可多個(gè)),葉子節(jié)點(diǎn)是沒(méi)有子節(jié)點(diǎn)的末端節(jié)點(diǎn)。
TreeView 常見(jiàn)應(yīng)用場(chǎng)景:文件目錄瀏覽、系統(tǒng)權(quán)限結(jié)構(gòu)展示、菜單導(dǎo)航、數(shù)據(jù)分類層級(jí)展示等。
二、基礎(chǔ)操作(WinForm 為例,最常用場(chǎng)景)
1. 環(huán)境準(zhǔn)備
在 Visual Studio 中創(chuàng)建 WinForm 項(xiàng)目,從 “工具箱” 中拖拽 TreeView 控件到窗體上(默認(rèn)命名為 treeView1),可通過(guò)屬性窗口設(shè)置其外觀(如大小、字體、背景色等)。
2. 核心:添加節(jié)點(diǎn)(TreeNode)
添加節(jié)點(diǎn)有設(shè)計(jì)時(shí)和運(yùn)行時(shí)兩種方式,運(yùn)行時(shí)添加更具靈活性,是實(shí)際開(kāi)發(fā)的主流方式。
- (1)設(shè)計(jì)時(shí)添加
選中 TreeView 控件,在屬性窗口中找到 Nodes 屬性,點(diǎn)擊右側(cè) “…” 按鈕,打開(kāi) “TreeNode 編輯器”,通過(guò) “添加根”“添加子節(jié)點(diǎn)” 按鈕創(chuàng)建層級(jí)結(jié)構(gòu),設(shè)置節(jié)點(diǎn)的 Text(顯示文本)、Name(唯一標(biāo)識(shí))等屬性,點(diǎn)擊 “確定” 即可完成靜態(tài)節(jié)點(diǎn)添加。 - (2)運(yùn)行時(shí)添加(3 種常用方式)
方式 1:直接創(chuàng)建 TreeNode 并添加(單個(gè) / 少量節(jié)點(diǎn))
// 1. 添加根節(jié)點(diǎn)
TreeNode rootNode1 = new TreeNode("計(jì)算機(jī)"); // 初始化節(jié)點(diǎn),指定顯示文本
treeView1.Nodes.Add(rootNode1); // 將根節(jié)點(diǎn)添加到 TreeView 的節(jié)點(diǎn)集合中
// 2. 給根節(jié)點(diǎn)添加子節(jié)點(diǎn)
TreeNode childNode1 = new TreeNode("本地磁盤 (C:)");
TreeNode childNode2 = new TreeNode("本地磁盤 (D:)");
rootNode1.Nodes.Add(childNode1); // 子節(jié)點(diǎn)添加到父節(jié)點(diǎn)的 Nodes 集合中
rootNode1.Nodes.Add(childNode2);
// 3. 嵌套添加孫子節(jié)點(diǎn)
TreeNode grandChildNode1 = new TreeNode("Windows 文件夾");
childNode1.Nodes.Add(grandChildNode1);
方式 2:批量添加節(jié)點(diǎn)(適合大量節(jié)點(diǎn))
// 先創(chuàng)建節(jié)點(diǎn)數(shù)組,再批量添加
TreeNode[] rootNodes = new TreeNode[]
{
new TreeNode("我的文檔"),
new TreeNode("我的圖片"),
new TreeNode("我的音樂(lè)")
};
treeView1.Nodes.AddRange(rootNodes); // 批量添加根節(jié)點(diǎn)
// 給“我的文檔”批量添加子節(jié)點(diǎn)
TreeNode[] docChildNodes = new TreeNode[]
{
new TreeNode("工作文檔"),
new TreeNode("個(gè)人文檔"),
new TreeNode("臨時(shí)文檔")
};
treeView1.Nodes[1].Nodes.AddRange(docChildNodes); // 通過(guò)索引獲取根節(jié)點(diǎn),再添加子節(jié)點(diǎn)數(shù)組
方式 3:簡(jiǎn)化寫法(直接傳入文本添加)
// 直接添加根節(jié)點(diǎn)(無(wú)需顯式創(chuàng)建 TreeNode 實(shí)例)
treeView1.Nodes.Add("網(wǎng)絡(luò)鄰居");
// 給指定根節(jié)點(diǎn)添加子節(jié)點(diǎn)(鏈?zhǔn)綄懛ǎ?
treeView1.Nodes[3].Nodes.Add("無(wú)線網(wǎng)絡(luò)");
treeView1.Nodes[3].Nodes.Add("有線網(wǎng)絡(luò)");
3. 節(jié)點(diǎn)的常用操作(修改、刪除、查找、展開(kāi) / 折疊)
- (1)修改節(jié)點(diǎn)
// 1. 通過(guò)索引查找節(jié)點(diǎn)并修改文本
treeView1.Nodes[0].Text = "我的電腦(修改后)";
// 2. 通過(guò)節(jié)點(diǎn)名稱查找并修改(設(shè)計(jì)時(shí)或創(chuàng)建時(shí)指定 Name 屬性)
TreeNode targetNode = treeView1.Nodes.Find("nodeDoc", true)[0]; // true 表示遞歸查找所有子節(jié)點(diǎn)
targetNode.Text = "我的文檔(修改后)";
// 3. 設(shè)置節(jié)點(diǎn)附加數(shù)據(jù)(Tag 屬性,可存儲(chǔ)任意對(duì)象)
childNode1.Tag = new { DiskType = "系統(tǒng)盤", Capacity = "500GB" };
- (2)刪除節(jié)點(diǎn)
// 1. 刪除選中的節(jié)點(diǎn)
if (treeView1.SelectedNode != null)
{
treeView1.SelectedNode.Remove();
}
// 2. 刪除指定根節(jié)點(diǎn)
treeView1.Nodes.RemoveAt(3); // 刪除索引為 3 的根節(jié)點(diǎn)
// 3. 清空所有節(jié)點(diǎn)
treeView1.Nodes.Clear();
- (3)展開(kāi) / 折疊節(jié)點(diǎn)
// 1. 展開(kāi)指定節(jié)點(diǎn)(包含所有子節(jié)點(diǎn))
treeView1.Nodes[0].ExpandAll();
// 2. 折疊指定節(jié)點(diǎn)(包含所有子節(jié)點(diǎn))
treeView1.Nodes[0].Collapse();
// 3. 切換節(jié)點(diǎn)的展開(kāi)/折疊狀態(tài)(點(diǎn)擊節(jié)點(diǎn)時(shí)常用)
if (treeView1.SelectedNode != null)
{
treeView1.SelectedNode.Toggle();
}
// 4. 展開(kāi)所有根節(jié)點(diǎn)(不展開(kāi)子節(jié)點(diǎn))
foreach (TreeNode node in treeView1.Nodes)
{
node.Expand();
}
三、關(guān)鍵事件:響應(yīng)節(jié)點(diǎn)交互
TreeView 控件的核心交互事件用于捕獲用戶操作,最常用的有以下兩個(gè):
- AfterSelect 事件(節(jié)點(diǎn)選中后觸發(fā))
當(dāng)用戶點(diǎn)擊(或通過(guò)鍵盤切換)選中某個(gè)節(jié)點(diǎn)時(shí)觸發(fā),常用于獲取選中節(jié)點(diǎn)的信息并執(zhí)行后續(xù)邏輯。
事件綁定與實(shí)現(xiàn)
// 方式1:通過(guò)窗體設(shè)計(jì)器綁定(選中 TreeView,雙擊屬性窗口中的 AfterSelect 事件)
// 方式2:運(yùn)行時(shí)手動(dòng)綁定(窗體構(gòu)造函數(shù)中)
public Form1()
{
InitializeComponent();
treeView1.AfterSelect += new TreeViewEventHandler(treeView1_AfterSelect);
}
// AfterSelect 事件處理方法
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
// e.Node 表示當(dāng)前選中的節(jié)點(diǎn)
if (e.Node != null)
{
// 顯示選中節(jié)點(diǎn)的信息
string nodeInfo = $"選中節(jié)點(diǎn):{e.Node.Text}\n節(jié)點(diǎn)層級(jí):{GetNodeLevel(e.Node)}";
if (e.Node.Tag != null)
{
nodeInfo += $"\n附加數(shù)據(jù):{e.Node.Tag.ToString()}";
}
MessageBox.Show(nodeInfo);
}
}
// 輔助方法:獲取節(jié)點(diǎn)層級(jí)(根節(jié)點(diǎn)層級(jí)為 0)
private int GetNodeLevel(TreeNode node)
{
int level = 0;
TreeNode currentNode = node;
while (currentNode.Parent != null)
{
level++;
currentNode = currentNode.Parent;
}
return level;
}
2. NodeMouseClick 事件(節(jié)點(diǎn)鼠標(biāo)點(diǎn)擊觸發(fā))
當(dāng)用戶用鼠標(biāo)點(diǎn)擊節(jié)點(diǎn)時(shí)觸發(fā),可區(qū)分點(diǎn)擊的鼠標(biāo)按鍵(左鍵、右鍵),常用于實(shí)現(xiàn)右鍵菜單等功能。
事件實(shí)現(xiàn)(右鍵菜單示例)
// 窗體構(gòu)造函數(shù)中綁定事件
public Form1()
{
InitializeComponent();
treeView1.NodeMouseClick += new TreeNodeMouseClickEventHandler(treeView1_NodeMouseClick);
}
// NodeMouseClick 事件處理方法
private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
// 右鍵點(diǎn)擊節(jié)點(diǎn)時(shí)顯示自定義菜單
if (e.Button == MouseButtons.Right)
{
// 選中當(dāng)前點(diǎn)擊的節(jié)點(diǎn)(避免右鍵點(diǎn)擊未選中節(jié)點(diǎn))
treeView1.SelectedNode = e.Node;
// 創(chuàng)建右鍵菜單
ContextMenuStrip contextMenu = new ContextMenuStrip();
contextMenu.Items.Add("查看節(jié)點(diǎn)信息");
contextMenu.Items.Add("-"); // 分隔線
contextMenu.Items.Add("修改節(jié)點(diǎn)文本");
contextMenu.Items.Add("刪除節(jié)點(diǎn)");
// 菜單點(diǎn)擊事件
contextMenu.Items[0].Click += (s, args) =>
{
MessageBox.Show($"節(jié)點(diǎn)信息:{e.Node.Text}");
};
contextMenu.Items[2].Click += (s, args) =>
{
e.Node.Text = "修改后的節(jié)點(diǎn)(右鍵菜單)";
};
contextMenu.Items[3].Click += (s, args) =>
{
e.Node.Remove();
};
// 顯示右鍵菜單
contextMenu.Show(treeView1, e.Location);
}
}
四、高級(jí)應(yīng)用:動(dòng)態(tài)加載樹(shù)形數(shù)據(jù)(懶加載)
在實(shí)際開(kāi)發(fā)中,若樹(shù)形數(shù)據(jù)量較大(如文件目錄、海量分類數(shù)據(jù)),一次性加載所有節(jié)點(diǎn)會(huì)導(dǎo)致界面卡頓,此時(shí)常用懶加載(按需加載):僅加載根節(jié)點(diǎn),當(dāng)用戶展開(kāi)某個(gè)節(jié)點(diǎn)時(shí),再動(dòng)態(tài)加載其下的子節(jié)點(diǎn)。實(shí)現(xiàn)思路
- 1、初始化時(shí)僅加載根節(jié)點(diǎn),并給每個(gè)根節(jié)點(diǎn)標(biāo)記 “未加載子節(jié)點(diǎn)”(可通過(guò) Tag 屬性或自定義節(jié)點(diǎn)擴(kuò)展)。
- 2、綁定 TreeView 的 BeforeExpand 事件(節(jié)點(diǎn)展開(kāi)前觸發(fā))。
- 3、在事件中判斷當(dāng)前節(jié)點(diǎn)是否已加載子節(jié)點(diǎn),若未加載則動(dòng)態(tài)獲取數(shù)據(jù)并添加子節(jié)點(diǎn),同時(shí)標(biāo)記為 “已加載”。
代碼實(shí)現(xiàn)(模擬文件目錄懶加載)
// 窗體構(gòu)造函數(shù):初始化根節(jié)點(diǎn)
public Form1()
{
InitializeComponent();
treeView1.BeforeExpand += new TreeViewCancelEventHandler(treeView1_BeforeExpand);
// 初始化根節(jié)點(diǎn)(模擬“我的電腦”,標(biāo)記為未加載子節(jié)點(diǎn))
TreeNode rootNode = new TreeNode("我的電腦");
rootNode.Tag = false; // false = 未加載子節(jié)點(diǎn),true = 已加載子節(jié)點(diǎn)
treeView1.Nodes.Add(rootNode);
}
// BeforeExpand 事件:懶加載子節(jié)點(diǎn)
private void treeView1_BeforeExpand(object sender, TreeViewCancelEventArgs e)
{
TreeNode currentNode = e.Node;
// 判斷是否已加載子節(jié)點(diǎn)(通過(guò) Tag 屬性判斷)
if (currentNode.Tag != null && (bool)currentNode.Tag == false)
{
// 清空臨時(shí)節(jié)點(diǎn)(若有),避免重復(fù)加載
currentNode.Nodes.Clear();
// 模擬動(dòng)態(tài)獲取子節(jié)點(diǎn)數(shù)據(jù)(實(shí)際開(kāi)發(fā)中可替換為數(shù)據(jù)庫(kù)查詢、文件目錄讀取等)
List<string> childNodeNames = GetChildNodeData(currentNode.Text);
// 添加子節(jié)點(diǎn),并標(biāo)記為未加載(后續(xù)可繼續(xù)展開(kāi)加載孫子節(jié)點(diǎn))
foreach (string nodeName in childNodeNames)
{
TreeNode childNode = new TreeNode(nodeName);
childNode.Tag = false; // 子節(jié)點(diǎn)默認(rèn)未加載孫子節(jié)點(diǎn)
currentNode.Nodes.Add(childNode);
}
// 標(biāo)記當(dāng)前節(jié)點(diǎn)為已加載,避免重復(fù)觸發(fā)加載
currentNode.Tag = true;
}
}
// 模擬獲取子節(jié)點(diǎn)數(shù)據(jù)的方法
private List<string> GetChildNodeData(string parentNodeText)
{
List<string> childNodes = new List<string>();
switch (parentNodeText)
{
case "我的電腦":
childNodes.AddRange(new string[] { "本地磁盤 (C:)", "本地磁盤 (D:)", "本地磁盤 (E:)" });
break;
case "本地磁盤 (C:)":
childNodes.AddRange(new string[] { "Windows", "Program Files", "Users" });
break;
case "本地磁盤 (D:)":
childNodes.AddRange(new string[] { "工作文件", "娛樂(lè)視頻", "備份數(shù)據(jù)" });
break;
case "本地磁盤 (E:)":
childNodes.AddRange(new string[] { "照片", "音樂(lè)", "軟件安裝包" });
break;
default:
childNodes.Add("空文件夾");
break;
}
return childNodes;
}
五、補(bǔ)充說(shuō)明
- 1、WPF 中的 TreeView:WinForm 的 TreeView 偏向傳統(tǒng)桌面應(yīng)用,WPF 中的 TreeView 支持?jǐn)?shù)據(jù)綁定(ItemsSource)、模板自定義(DataTemplate),更適合現(xiàn)代化界面,核心思想(層級(jí)結(jié)構(gòu)、節(jié)點(diǎn)操作)與 WinForm 一致,但實(shí)現(xiàn)方式更靈活。
- 2、節(jié)點(diǎn)圖標(biāo)設(shè)置:可通過(guò) ImageList 控件配合 TreeView 的 ImageList、ImageIndex、SelectedImageIndex 屬性為節(jié)點(diǎn)設(shè)置普通狀態(tài)和選中狀態(tài)的圖標(biāo)。
- 3、性能優(yōu)化:處理大量節(jié)點(diǎn)時(shí),可先調(diào)用 treeView1.BeginUpdate() 暫停界面刷新,操作完成后調(diào)用 treeView1.EndUpdate() 恢復(fù)刷新,避免界面閃爍。
六、總結(jié)
- 1、TreeView 核心是TreeNode 節(jié)點(diǎn)的層級(jí)管理,節(jié)點(diǎn)的添加、刪除、修改是基礎(chǔ)操作,通過(guò) Nodes 集合實(shí)現(xiàn)。
- 2、常用交互依賴 AfterSelect(選中)和 NodeMouseClick(鼠標(biāo)點(diǎn)擊)事件,可滿足大部分交互場(chǎng)景。
- 3、大數(shù)據(jù)量場(chǎng)景下,** 懶加載(BeforeExpand 事件按需加載)** 是提升性能的關(guān)鍵。
- 4、開(kāi)發(fā)中可通過(guò) Tag 屬性存儲(chǔ)節(jié)點(diǎn)附加數(shù)據(jù),通過(guò) BeginUpdate()/EndUpdate() 優(yōu)化界面刷新性能。
到此這篇關(guān)于C# TreeView 控件的詳解與應(yīng)用小結(jié)的文章就介紹到這了,更多相關(guān)C# TreeView 控件內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#微信公眾號(hào)開(kāi)發(fā)之使用MessageHandler簡(jiǎn)化消息處理流程
這篇文章介紹了C#微信公眾號(hào)開(kāi)發(fā)之使用MessageHandler簡(jiǎn)化消息處理流程,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-06-06
C#實(shí)現(xiàn)對(duì)字符串中特定詞出現(xiàn)次數(shù)的計(jì)數(shù)過(guò)程
LINQ(Language-Integrated Query)是C#和VB.NET中強(qiáng)大的查詢語(yǔ)言,它可以用來(lái)查詢集合、SQL數(shù)據(jù)庫(kù)、XML文檔等,在C#中,我們可以使用LINQ來(lái)簡(jiǎn)化對(duì)字符串中特定單詞出現(xiàn)次數(shù)的計(jì)數(shù)過(guò)程,需要的朋友可以參考下2024-08-08
利用C#開(kāi)發(fā)瀏覽器擴(kuò)展的全過(guò)程記錄
做web開(kāi)發(fā)的同學(xué),經(jīng)常會(huì)用到各種chrome瀏覽器插件,那么我們寄幾怎么開(kāi)發(fā)一個(gè)插件呢(其實(shí)是瀏覽器擴(kuò)展)?這篇文章主要給大家介紹了關(guān)于利用C#開(kāi)發(fā)瀏覽器擴(kuò)展的相關(guān)資料,需要的朋友可以參考下2021-07-07
C#面向?qū)ο缶幊讨幸蕾嚪崔D(zhuǎn)原則的示例詳解
在面向?qū)ο缶幊讨校琒OLID?是五個(gè)設(shè)計(jì)原則的首字母縮寫,旨在使軟件設(shè)計(jì)更易于理解、靈活和可維護(hù)。本文將通過(guò)實(shí)例詳細(xì)講講C#面向?qū)ο缶幊讨幸蕾嚪崔D(zhuǎn)原則,需要的可以參考一下2022-07-07
C#使用Protocol Buffer(ProtoBuf)進(jìn)行Unity中的Socket通信
這篇文章主要介紹了C#使用Protocol Buffer(ProtoBuf)進(jìn)行Unity的Socket通信的實(shí)例,Protocol Buffer是Google開(kāi)發(fā)的數(shù)據(jù)格式,也是除了XML和JSON之外人氣第三高的^^需要的朋友可以參考下2016-04-04
C#?PictureBox控件方法參數(shù)及圖片刪除重命名上傳詳解
這篇文章主要為大家介紹了C#?PictureBox控件方法參數(shù)及圖片刪除重命名上傳示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-08-08
使用WPF在Windows實(shí)現(xiàn)任務(wù)欄縮略圖效果
這篇文章主要為大家詳細(xì)介紹了如何使用WPF在Windows實(shí)現(xiàn)任務(wù)欄縮略圖效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2025-06-06

