Winfrom TreeView应用,节点添加,禁用节点,自动切换节点

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

23.gif

核心代码

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