效果图,源码下载地址: https://pan.baidu.com/s/1BbaUtzqMsKNj3PtT6IsncQ?pwd=q245 提取码: q245

核心代码
using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
namespace TreeViewDemo
{
public class TreeViewEnhanced : TreeView
{
protected override void WndProc(ref Message m)
{
this.DrawMode = TreeViewDrawMode.OwnerDrawText;
if (m.Msg == 0x203) { m.Result = IntPtr.Zero; }
else base.WndProc(ref m);
}
public TreeViewEnhanced()
{
this.DrawNode += new DrawTreeNodeEventHandler(this.treeViewEnhanced1_DrawNode);
this.NodeMouseClick += new TreeNodeMouseClickEventHandler(this.treeViewEnhanced1_NodeMouseClick);
this.AfterCheck += new TreeViewEventHandler(this.treeViewEnhanced1_AfterCheck);
this.BeforeSelect += new TreeViewCancelEventHandler(this.treeViewEnhanced1_BeforeSelect);
this.CheckBoxes = true;
}
/// <summary>
/// 绑定TreeView(利用TreeNodeCollection)
/// </summary>
/// <param name="tnc">TreeNodeCollection(TreeView的节点集合)</param>
/// <param name="pid">父id的值</param>
/// <param name="idColName">数据库 id 字段名</param>
/// <param name="pidColName">数据库 父id 字段名</param>
/// <param name="idValColName">数据库 文本 字段名</param>
/// <param name="enabled">是否启用 字段名</param>
public void Bind_Tv(DataTable dt, TreeNodeCollection tnc, int pid, string idColName, string pidColName, string idValColName, string enabled)
{
DataView dv = new DataView(dt);//将DataTable存到DataView中,以便于筛选数据
TreeNode tn;//建立TreeView的节点(TreeNode),以便将取出的数据添加到节点中
//构建“父id字段=父id字段值”的查询条件
string filter = $"{pidColName}={pid}";
dv.RowFilter = filter;//利用DataView将数据进行筛选,选出相同 父id值 的数据
foreach (DataRowView drv in dv)
{
tn = new TreeNode();//建立一个新节点(学名叫:一个实例)
tn.Name = drv[idColName].ToString();//节点的Value值,一般为数据库的id值
tn.Text = drv[idValColName].ToString();//节点的Text,节点的文本显示
tn.Tag = drv[enabled];
tnc.Add(tn);//将该节点加入到TreeNodeCollection(节点集合)中
int pidVal;
if (int.TryParse(tn.Name, out pidVal))
{
Bind_Tv(dt, tn.Nodes, pidVal, idColName, pidColName, idValColName, enabled);//递归(反复调用这个方法,直到把数据取完为止)
}
}
}
private void treeViewEnhanced1_DrawNode(object sender, DrawTreeNodeEventArgs e)
{
TreeNode treeNode = e.Node;
TreeView treeview = sender as TreeView;
var brush = Brushes.Black;
if ("0".Equals(treeNode.Tag.ToString()))
{
brush = Brushes.Gray;
treeNode.Checked = false;
}
if (treeNode != null && treeNode.Nodes.Count > 0)
{
if ("0".Equals(treeNode.Tag.ToString()))
{
foreach (TreeNode node in treeNode.Nodes)
{
node.Tag = 0;
node.Checked = false;
}
}
else
{
int isCheckedCount = 0, isNoCheckedCount = 0;
foreach (TreeNode node in treeNode.Nodes)
{
if (node.Checked)
{
isCheckedCount++;
}
else
{
isNoCheckedCount++;
}
}
if (isCheckedCount > 0 && isNoCheckedCount > 0)
{
var location = e.Node.Bounds.Location;
location.Offset(-11, 2);
var size = new Size(9, 9);
//brush = Brushes.Blue;
e.Graphics.FillRectangle(brush, new Rectangle(location, size));
}
else if (isCheckedCount > 0)
{
treeNode.Checked = true;
}
else if (isNoCheckedCount > 0)
{
treeNode.Checked = false;
}
}
}
//绘制文本
e.Graphics.DrawString(e.Node.Text, treeview.Font, brush, e.Bounds.Left, e.Bounds.Top);
}
private void treeViewEnhanced1_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e)
{
TreeView treeView = sender as TreeView;
if (treeView != null)
{
treeView.Refresh();
}
}
private void treeViewEnhanced1_AfterCheck(object sender, TreeViewEventArgs e)
{
//只处理鼠标点击引起的状态变化
if (e.Action == TreeViewAction.ByMouse)
{
//更新子节点状态
UpdateChildNodes(e.Node);
}
}
private void UpdateChildNodes(TreeNode node)
{
bool state = node.Checked;
foreach (TreeNode child in node.Nodes)
{
child.Checked = state;
UpdateChildNodes(child);
}
}
private void treeViewEnhanced1_BeforeSelect(object sender, TreeViewCancelEventArgs e)
{
if ("0".Equals(e.Node.Tag.ToString()))
e.Cancel = true;
}
}
}添加到treeView节点的数据TestData.json
[
{
"id": 0,
"idVal": "一般检查",
"pid": -1,
"enabled": 1
},
{
"id": 1,
"idVal": "外观检查",
"pid": 0,
"enabled": 1
},
{
"id": 2,
"idVal": "标志检查",
"pid": 0,
"enabled": 0
},
{
"id": 3,
"idVal": "尺寸检查",
"pid": 0,
"enabled": 1
},
{
"id": 4,
"idVal": "基本构成检查",
"pid": 0,
"enabled": 1
},
{
"id": 5,
"idVal": "充电模式和连接方式检查",
"pid": 0,
"enabled": 1
},
{
"id": 6,
"idVal": "充电连接装置检查",
"pid": 0,
"enabled": 1
},
{
"id": 7,
"idVal": "电缆管理及储存检查",
"pid": 0,
"enabled": 1
},
{
"id": 8,
"idVal": "机械开关设备检查",
"pid": 0,
"enabled": 1
},
{
"id": 9,
"idVal": "防雷措施检查",
"pid": 0,
"enabled": 1
},
{
"id": 10,
"idVal": "防盗措施检查",
"pid": 0,
"enabled": 1
},
{
"id": 11,
"idVal": "通用器件符合性检查",
"pid": 0,
"enabled": 1
},
{
"id": 12,
"idVal": "专用部件符合性检查",
"pid": 0,
"enabled": 1
}
]将数据添加到TreeView和自动切换节点
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
string testData = File.ReadAllText("testData.json");
DataTable dt = JsonConvert.DeserializeObject<DataTable>(testData);
treeViewEnhanced1.Bind_Tv(dt, treeViewEnhanced1.Nodes, -1, "id", "pid", "idVal", "enabled");
treeViewEnhanced1.ExpandAll();
treeViewEnhanced1.Refresh();
}
Thread th;
private void button1_Click(object sender, EventArgs e)
{
if (th == null || !th.IsAlive)
{
th = new Thread(Test);
th.IsBackground = true;
th.Start();
}
}
private void Test()
{
foreach (TreeNode tn in treeViewEnhanced1.Nodes[0].Nodes)
{
if (tn.Checked)
{
this.BeginInvoke(new Action(() =>
{
treeViewEnhanced1.Focus();
treeViewEnhanced1.SelectedNode = tn;
label1.Text = $"正在测试【{tn.Text}】";
}));
Thread.Sleep(800);
}
}
this.BeginInvoke(new Action(() =>
{
label1.Text = "测试完成";
MessageBox.Show("测试完成");
}));
}
}本文来自 www.luofenming.com