C# WinForm TreeView 树形控件+ListView控件+菜单栏

📅 2026/6/16 9:07:12
C# WinForm TreeView 树形控件+ListView控件+菜单栏
本次案例基于WinForm框架使用TreeView控件实现树形节点创建、层级嵌套、新增节点、删除节点、获取选中节点等基础功能下面对全部代码进行分段拆解、逐行讲解包含语法含义、属性作用、设计逻辑。一、整体命名空间与窗体类定义namespace _2TreeView { public partial class Form1 : Form { // 后续所有方法、构造函数全部写在该类内部 } }代码解析namespace _2TreeView命名空间作用是隔离代码避免项目中类名重名冲突该命名空间名称由项目创建时自动生成和项目文件夹名称保持一致。public partial class Form1定义窗体类Form1public访问修饰符代表该类公开项目内所有代码都可以访问partial分部类核心作用是将一个类的代码拆分到多个文件中。WinForm窗体默认分为两个文件Form1.cs我们编写逻辑的文件、Form1.Designer.cs系统自动生成存放控件初始化代码: Form类的继承Form1继承自系统自带的Form窗体基类继承后Form1自动拥有窗体的所有基础能力窗口显示、最大化、关闭、承载控件等。二、窗体构造函数初始化树形节点构造函数在窗体启动时自动执行主要用于初始化页面所有树形节点搭建多层级树形结构。// 窗体构造函数窗体加载时自动执行 public Form1() { // 初始化窗体上所有拖拽的控件TreeView、Button等 InitializeComponent(); // 1. 创建树形顶级根节点 TreeNode root new TreeNode(明星); // 2. 创建根节点的一级子节点 TreeNode childNode1 new TreeNode(小罗); TreeNode childNode2 new TreeNode(卡卡); TreeNode childNode3 new TreeNode(大罗); // 3. 创建【卡卡】节点的二级子节点嵌套子节点 TreeNode childNode2_1 new TreeNode(卡卡1); TreeNode childNode2_2 new TreeNode(卡卡2); TreeNode childNode2_3 new TreeNode(卡卡3); // 4. 将二级子节点添加到卡卡一级节点中形成嵌套层级 childNode2.Nodes.Add(childNode2_1); childNode2.Nodes.Add(childNode2_2); childNode2.Nodes.Add(childNode2_3); // 5. 将一级子节点全部添加到顶级根节点中 root.Nodes.Add(childNode1); root.Nodes.Add(childNode2); root.Nodes.Add(childNode3); // 6. 将根节点添加到TreeView控件中绑定到页面控件 treeView1.Nodes.Add(root); // 7. 默认展开TreeView所有层级节点 treeView1.ExpandAll(); }逐行详细解析InitializeComponent();系统固定方法自动读取Designer文件中的控件配置初始化我们拖拽到窗体上的treeView1、button1、button2等控件所有WinForm窗体构造函数必须执行该方法否则控件无法显示。TreeNode root new TreeNode(明星);实例化TreeNode节点对象创建树形结构的顶级根节点节点显示文本为“明星”。TreeNode是TreeView控件的核心类代表树形结构中的每一个节点。创建一级子节点new TreeNode(名称)分别创建小罗、卡卡、大罗三个独立节点此时节点为孤立状态未归属任何父节点。创建二级子节点专门为【卡卡】节点创建3个子节点卡卡1/2/3用于演示TreeView多层级嵌套结构。childNode2.Nodes.Add(节点对象);Nodes节点集合属性每个TreeNode节点都自带该属性用于存储自身的所有子节点Add()集合专属方法作用是将指定子节点添加到当前父节点的集合中此步骤完成后卡卡节点下包含3个二级子节点形成二级树形结构。root.Nodes.Add(childNode1);将三个一级子节点统一添加到顶级根节点【明星】下至此完整的树形数据结构搭建完成。treeView1.Nodes.Add(root);将封装好的根节点绑定到页面的treeView1控件。区别root是内存中的数据节点treeView1是页面可视化控件此代码实现数据绑定页面才能展示树形结构。treeView1.ExpandAll();控件方法自动展开TreeView所有层级的节点无需手动点击加号展开如果删除该代码页面节点默认全部折叠。三、button1点击事件新增一级节点功能点击按钮1在根节点【明星】下新增一个文本为string的一级子节点。// 新增节点按钮点击事件 private void button1_Click(object sender, EventArgs e) { // 实例化新的树形节点显示文本为string TreeNode t1 new TreeNode(string); // 获取TreeView的第0个根节点明星并向其添加子节点 treeView1.Nodes[0].Nodes.Add(t1); }逐行详细解析方法参数object sender代表触发事件的控件此处为button1EventArgs e封装点击事件的附加参数系统默认参数固定写法。TreeNode t1 new TreeNode(string);创建一个全新的空白节点展示文本为string。treeView1.Nodes[0]treeView1.Nodes代表控件所有顶级根节点集合索引0对应我们初始化创建的【明星】根节点。treeView1.Nodes[0].Nodes.Add(t1);获取根节点的子节点集合并将新节点t1添加进去实现动态新增节点。四、节点鼠标点击事件获取选中节点信息功能鼠标点击任意树形节点在控制台输出节点文本对比两种获取节点方式的区别。// 节点鼠标点击事件 private void treeView1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) { // 方式1通过控件属性获取选中节点 Console.WriteLine(treeView1.SelectedNode); // 方式2通过事件参数获取当前点击节点 Console.WriteLine(e.Node.Text); }逐行详细解析事件参数TreeNodeMouseClickEventArgs e专属TreeView节点点击事件的参数相比普通点击事件额外封装了点击节点的所有信息。treeView1.SelectedNodeTreeView控件自带属性用于获取上一次选中的节点触发原理鼠标点击瞬间SelectedNode还未完成更新所以获取的是旧选中节点存在数据延迟。e.Node.Text从事件参数中直接获取当前实时点击的节点Text属性代表节点的展示文本推荐使用该方式获取点击节点。Console.WriteLine()在VS控制台窗口打印内容用于调试查看节点数据。五、button2点击事件删除指定节点功能点击按钮2遍历根节点下所有一级子节点删除所有文本为string的节点同时讲解错误遍历方式与正确遍历方式的区别。1、被注释的错误写法foreach遍历删除// 错误写法foreach遍历集合时禁止直接删除元素 //foreach (TreeNode node in treeView1.Nodes[0].Nodes) //{ // if (node.Textstring) // { // node.Parent.Nodes.Remove(node); // } //}错误原因foreach是只读遍历模式遍历过程中集合长度不允许发生变化新增/删除元素如果强行删除会直接抛出集合已修改可能无法执行枚举操作的程序异常。2、正确写法倒序for循环删除// 删除指定节点按钮点击事件 private void button2_Click(object sender, EventArgs e) { // 倒序遍历根节点下所有一级子节点 for (int i treeView1.Nodes[0].Nodes.Count-1; i 0; i--) { // 根据索引获取当前遍历的节点 TreeNode t1 treeView1.Nodes[0].Nodes[i]; // 判断节点文本是否为需要删除的string if (t1.Text string) { // 通过父节点集合移除当前节点 t1.Parent.Nodes.Remove(t1); } } }逐行详细解析treeView1.Nodes[0].Nodes.Count-1获取根节点子节点集合的最后一个元素索引作为循环起始值。i 0; i--从最后一个节点向前倒序遍历优势删除节点后后续节点索引不会发生变动不会出现遍历漏元素、程序报错问题。TreeNode t1 treeView1.Nodes[0].Nodes[i];通过索引获取当前循环对应的节点对象。if (t1.Text string)筛选目标节点匹配需要删除的节点文本。t1.Parent.Nodes.Remove(t1);Parent属性获取当前节点的直属父节点Remove(节点对象)集合删除方法从父节点的子节点集合中移除指定节点对象。六、补充空白点击事件// TreeView控件空白区域点击事件本案例未编写业务逻辑 private void treeView1_Click(object sender, EventArgs e) { }该事件为点击TreeView空白区域时触发和节点点击事件相互独立本案例仅自动生成事件方法无实际业务代码可根据需求拓展功能如清空选中节点、新增默认节点等。七、核心知识点总结树形结构层级TreeView控件 顶级根节点 一级子节点 二级子节点多层级无限嵌套核心类与属性TreeNode节点实体、Nodes子节点集合、Parent父节点、Text节点展示文本常用方法Add()新增节点、Remove()删除节点、ExpandAll()展开所有节点删除节点规范禁止foreach遍历删除统一使用倒序for循环执行删除操作。——————————ListView控件——————————次代码基于WinForm框架实现 ListView 控件模拟电脑磁盘/文件夹资源管理器的效果包含图标绑定、视图模式设置、表头添加、数据绑定、数据删除等全套基础功能。下面逐模块拆解所有代码通俗易懂讲解每一处功能。一、整体代码结构概述该代码属于WinForm窗体后台代码隶属于自定义命名空间在窗体初始化构造方法中完成ListView控件的所有配置与数据填充最终实现带表头、多列数据、支持大小图标切换的资源列表界面。namespace _3ListView { public partial class Form1 : Form { // 窗体构造方法程序启动、窗体加载时自动执行 public Form1() { // 所有控件初始化、配置、数据绑定代码 } } }二、逐模块详细解析1. 命名空间定义namespace _3ListView作用命名空间相当于代码的“文件夹”用于隔离不同功能的代码防止项目中出现类名重复、代码冲突问题。补充_3ListView 是当前项目自定义命名空间项目内所有窗体、工具类、方法都可以收纳在该命名空间下。2. 窗体类定义public partial class Form1 : Formpublic访问修饰符代表该窗体类公开项目内所有代码都可以访问这个窗体。partial分部类关键字核心作用将一个窗体类拆分到两个文件中。Form1.cs当前文件存放开发者手写的业务逻辑代码数据绑定、控件配置Form1.Designer.cs系统自动生成存放拖拽控件、控件属性初始化代码: Form类的继承代表Form1是一个Windows窗体继承父类Form的所有能力窗口显示、控件承载、弹窗、关闭等基础窗口功能。3. 窗体构造方法public Form1() { InitializeComponent(); // 后续所有配置代码 }构造方法与类名必须同名窗体被实例化打开窗口时自动优先执行构造方法内的所有代码。InitializeComponent();固定必备代码调用系统自动生成的方法初始化窗体上所有拖拽的控件ListView、ImageList、按钮等如果缺失该代码所有控件无法显示。4. 绑定图标控件ListView图标配置//设置listview大图标的集合 listView2.LargeImageList imageList1; //设置listview小图标的集合 listView2.SmallImageList imageList2;业务场景ListView控件展示数据时支持大图标、小图标、详情、列表等多种模式图标需要提前存放在ImageList控件中。LargeImageList 属性绑定大图标容器imageList1当ListView切换为【大图标视图】时自动从imageList1中读取图标。SmallImageList 属性绑定小图标容器imageList2当ListView切换为【小图标/详情视图】时自动从imageList2中读取图标。补充imageList1、imageList2 需要提前在窗体设计界面拖拽添加并手动导入对应的图标图片。5. 设置ListView展示视图模式listView2.View View.Details;//设置展示的风格View是ListView的核心属性用于控制数据展示样式枚举类型一共5种可选模式5种视图模式详解View.Details详情模式当前代码使用带表头、多列展示数据和电脑资源管理器详情界面一致支持展示名称、时间、大小等多维度数据View.LargeIcon大图标模式仅展示大图标单行文字无表头View.SmallIcon小图标模式仅展示小图标单行文字无表头View.List列表模式横向排列小图标数据无表头View.Tile平铺模式Win10/Win11资源管理器平铺样式。6. 添加ListView表头数据列listView2.Columns.Add(名称); //添加一列 listView2.Columns.Add(修改时间); listView2.Columns.Add(类型); listView2.Columns.Add(大小);ColumnsListView的列集合专门用来存储所有表头仅在Details详情模式下生效Columns.Add(表头名称)新增一列表头代码依次添加4列名称、修改时间、类型、大小对应界面效果窗口顶部会出现4个列表头后续添加的数据项会自动对应归属到对应的列下方。7. 创建数据项ListView主项子项ListView的数据结构分为两层主项ListViewItem 第一列数据子项SubItems 第二列及以后所有列数据下面以三组数据统一解析7.1 第一条数据win文件夹ListViewItem item1 new ListViewItem(win);//创建lsitview 项 item1.SubItems.Add(2026/2/1); item1.SubItems.Add(文件夹); item1.SubItems.Add(20G);new ListViewItem(win)实例化数据主项给第一列【名称】赋值为winSubItems.Add()给当前主项添加子数据依次对应后续表头第1个子项 → 修改时间2026/2/1第2个子项 → 类型文件夹第3个子项 → 大小20G7.2 第二条数据C盘ListViewItem item2 new ListViewItem(C盘);//创建lsitview 项 item2.SubItems.Add(2026/2/1); item2.SubItems.Add(文件夹); item2.SubItems.Add(202G);逻辑和item1完全一致新增一条磁盘数据填充四列完整信息。7.3 第三条数据D盘新增Name属性ListViewItem item3 new ListViewItem(D盘);//创建lsitview 项 item3.Name ss; item3.SubItems.Add(2026/2/1);//向每一项的子项添加 item3.SubItems.Add(文件夹); item3.SubItems.Add(208G);基础赋值逻辑同上额外新增item3.Name ssName属性作用给当前数据项设置唯一标识名称后续可以通过Name精准删除、查找该数据项是删除功能的核心依据。8. 将数据项添加到ListView控件listView2.Items.Add(item1); // 向控件里面添加每一项 listView2.Items.Add(item2); listView2.Items.Add(item3);ItemsListView的数据项集合所有展示的数据都存储在该集合中Items.Add(数据项)将我们手动创建的item1/item2/item3添加到ListView控件中只有执行该代码数据才会在界面上显示如果不执行Add方法仅创建ListViewItem对象数据仅存在内存中界面无任何展示。9. 注释代码三种数据删除方式重点拓展//listView2.Items.Remove(item1); //指定项进行移除 // listView2.Items.RemoveAt(1); // 根据索引进行删除 // listView2.Items.RemoveByKey(item3.Name); //根据name属性进行删除这三行代码为注释状态取消注释即可执行删除操作三种删除方式适配不同业务场景详细区别Remove(数据项对象)直接传入创建好的item对象如item1精准删除指定数据项适合提前定义变量、已知对象的场景。RemoveAt(索引值)根据下标索引删除ListView数据索引从0开始item10、item21、item32示例删除第二条数据item2适合批量遍历删除场景。RemoveByKey(Name值)根据数据项的Name属性删除示例中item3.Namess等价于RemoveByKey(ss)适合动态查找、无固定变量的删除场景安全性最高。三、整体运行效果总结程序运行后窗体中的listView2控件以详情模式展示顶部包含【名称、修改时间、类型、大小】4列表头界面展示win文件夹、C盘、D盘三条完整数据同时支持切换图标视图、三种方式删除任意一条数据完美复刻资源管理器基础功能。四、完整可运行代码using System; using System.Windows.Forms; namespace _3ListView { public partial class Form1 : Form { public Form1() { //初始化窗体及所有控件 InitializeComponent(); InitListView(); } /// summary /// 初始化ListView控件配置属性并绑定数据 /// /summary private void InitListView() { // 1、绑定图标集合给ListView设置大图标、小图标数据源 // LargeImageList适配大图标视图模式 listView2.LargeImageList imageList1; // SmallImageList适配小图标、详细信息视图模式 listView2.SmallImageList imageList2; // 2、设置展示模式为【详细信息模式】支持多列展示数据 listView2.View View.Details; // 3、添加列头对应文件资源的四大属性 listView2.Columns.Add(名称); // 资源名称 listView2.Columns.Add(修改时间); // 资源最后修改时间 listView2.Columns.Add(类型); // 资源文件类型 listView2.Columns.Add(大小); // 资源占用存储空间 // 4、创建第一个ListView数据项win文件夹 ListViewItem item1 new ListViewItem(win); // 给当前项添加子列数据 item1.SubItems.Add(2026/2/1); item1.SubItems.Add(文件夹); item1.SubItems.Add(20G); // 5、创建第二个ListView数据项C盘 ListViewItem item2 new ListViewItem(C盘); item2.SubItems.Add(2026/2/1); item2.SubItems.Add(文件夹); item2.SubItems.Add(202G); // 6、创建第三个ListView数据项D盘并设置唯一Name标识 ListViewItem item3 new ListViewItem(D盘); item3.Name ss; // 用于根据键值删除数据项 item3.SubItems.Add(2026/2/1); item3.SubItems.Add(文件夹); item3.SubItems.Add(208G); // 7、将创建好的所有数据项添加至ListView控件中 listView2.Items.Add(item1); listView2.Items.Add(item2); listView2.Items.Add(item3); // 拓展三种删除数据项的方式注释状态可按需开启测试 // 方式1直接指定对象删除win文件夹项 // listView2.Items.Remove(item1); // 方式2根据索引删除索引从0开始此处删除第二个项C盘 // listView2.Items.RemoveAt(1); // 方式3根据项的Name属性键值删除D盘 // listView2.Items.RemoveByKey(item3.Name); } } }————————菜单栏项目代码——————————该代码为C# WinForm桌面程序源码核心功能包含代码动态创建多级下拉菜单栏、通用菜单点击事件、颜色对话框、字体对话框、文件打开/保存对话框。下面拆分所有模块逐行进行精细化讲解。一、整体结构概述程序整体由命名空间、窗体类、构造方法、各类事件触发方法组成窗体绑定了菜单栏控件、富文本框、4个功能按钮、系统自带的五大对话框控件。二、窗体构造函数核心动态创建多级菜单构造函数在窗口初始化、程序启动时自动执行本模块核心功能动态创建一级、二级、三级下拉菜单栏。public Form1() { InitializeComponent(); // 注释开发者自定义的JSON格式菜单结构草稿仅作为开发参考无执行效果 /*[{ * one:偶像明星, * oneSubIems:[ ] * * },{},{},{},{}] */ // 1. 创建一级菜单 ToolStripMenuItem item1 new ToolStripMenuItem(偶像明星); // 2. 创建二级子菜单 ToolStripMenuItem item1_1 new ToolStripMenuItem(姆巴佩); ToolStripMenuItem item1_2 new ToolStripMenuItem(哈兰德); ToolStripMenuItem item1_3 new ToolStripMenuItem(姚明); // 3. 创建三级子菜单归属哈兰德 ToolStripMenuItem item1_2_1 new ToolStripMenuItem(魔人); ToolStripMenuItem item1_2_2 new ToolStripMenuItem(19岁); // 4. 绑定一级菜单与二级菜单 item1.DropDownItems.Add(item1_1); item1.DropDownItems.Add(item1_2); item1.DropDownItems.Add(item1_3); // 5. 绑定二级菜单与三级菜单 item1_2.DropDownItems.Add(item1_2_1); item1_2.DropDownItems.Add(item1_2_2); // 6. 绑定菜单点击事件 item1_1.Click Item1_1_Click; item1_3.Click Item1_1_Click; item1_2.Click Item1_1_Click; // 7. 将一级菜单添加到窗口菜单栏 menuStrip1.Items.Add(item1); }逐行细分讲解InitializeComponent(); WinForm固定初始化方法作用是加载设计界面拖拽的所有控件menuStrip1、button1~4、richTextBox1、各类对话框必须写在构造函数第一行否则控件无法使用。JSON注释块纯备注代码无任何执行作用。是开发者预先规划的菜单数据结构用来梳理一级菜单、子菜单的层级关系。ToolStripMenuItem.NET内置菜单控件类专门用于创建菜单栏的菜单选项new ToolStripMenuItem(文本)代表实例化菜单并设置菜单显示文字。菜单层级说明一级菜单偶像明星最顶层菜单二级菜单姆巴佩、哈兰德、姚明点击一级菜单弹出三级菜单魔人、19岁仅归属哈兰德点击哈兰德弹出DropDownItems.Add(控件) 核心绑定方法。给当前菜单添加下拉子项实现上下级菜单的关联。控件.Click 事件方法 事件绑定语法。将多个菜单的点击事件绑定到同一个方法Item1_1_Click减少重复代码所有绑定的菜单点击后都会触发该方法。menuStrip1.Items.Add(item1) 将创建好的一级菜单挂载到窗口顶部的菜单栏控件menuStrip1上最终让菜单显示在窗口中。三、所有自定义事件方法详解1. 未实现的菜单点击事件废弃方法private void Item1_3_Click(object sender, EventArgs e) { throw new NotImplementedException(); }解释该方法是系统自动生成的姚明菜单专属点击事件但开发者并未使用throw new NotImplementedException()主动抛出“未实现该功能”异常如果调用此方法程序会直接报错属于冗余废弃代码。2. 通用菜单点击事件核心菜单方法private void Item1_1_Click(object sender, EventArgs e) { MessageBox.Show(((ToolStripMenuItem)sender).Text); }逐行解释方法参数senderobject类型代表触发当前事件的控件本例中就是被点击的菜单EventArgs e封装事件附加参数菜单点击事件中无实际作用(ToolStripMenuItem)sender强制类型转换。因为sender默认是object基类类型无法直接读取菜单属性需要转为ToolStripMenuItem菜单类型.Text获取被点击菜单的显示文字如姆巴佩、哈兰德MessageBox.Show()弹出系统提示框展示被点击菜单的名称。3. 预设菜单【军事2】点击事件private void 军事2ToolStripMenuItem_Click(object sender, EventArgs e) { MessageBox.Show(军事2); }解释该菜单是开发者直接在设计界面拖拽创建的静态菜单非代码动态创建点击后直接弹出提示框固定显示文字“军事2”。4. 按钮1颜色对话框功能private void button1_Click(object sender, EventArgs e) { DialogResult r this.colorDialog1.ShowDialog(); if (rDialogResult.OK) { richTextBox1.ForeColor colorDialog1.Color; } }功能修改富文本框文字颜色详细解释colorDialog1.ShowDialog()弹出系统自带的颜色选择对话框DialogResult r接收对话框的操作返回值枚举类型rDialogResult.OK判断用户是否在颜色弹窗中点击【确定】按钮取消则不执行richTextBox1.ForeColor富文本框的文字颜色属性将用户选中的颜色赋值给该属性完成文字换色。5. 按钮2字体对话框功能private void button2_Click(object sender, EventArgs e) { if (this.fontDialog1.ShowDialog() DialogResult.OK) { //richTextBox1.Font fontDialog1.Font; richTextBox1.SelectionFont fontDialog1.Font; } }功能修改富文本框选中文本的字体样式详细解释fontDialog1.ShowDialog()弹出系统字体设置弹窗可设置字体、字号、加粗、斜体注释代码richTextBox1.Font作用是修改整个富文本框所有文字的字体生效代码SelectionFont仅修改鼠标选中的部分文字字体优先级更高也是本程序的设计逻辑。6. 按钮3文件打开对话框private void button3_Click(object sender, EventArgs e) { openFileDialog1.ShowDialog(); MessageBox.Show(openFileDialog1.FileName); }功能选取本地文件并获取文件完整路径openFileDialog1文件打开对话框控件用于浏览、选择本地电脑文件openFileDialog1.FileName获取选中文件的绝对完整路径包含盘符、文件夹、文件名、后缀最后通过弹窗展示该文件路径。7. 按钮4文件保存对话框private void button4_Click(object sender, EventArgs e) { saveFileDialog1.ShowDialog(); MessageBox.Show(saveFileDialog1.FileName); }功能自定义文件保存位置与名称并获取保存路径saveFileDialog1文件保存对话框控件用于选择保存文件夹、自定义文件名称FileName获取用户设置的保存完整路径弹窗展示路径信息。四、整体运行流程总结程序启动执行Form1构造函数初始化所有界面控件自动动态创建【偶像明星】多级菜单栏并绑定通用点击事件用户操作点击菜单弹窗展示对应菜单名称按钮1设置富文本文字颜色按钮2设置选中文本字体按钮3选择本地文件并查看路径按钮4设置文件保存位置并查看路径。