using System; using System.Windows.Forms; using System.Collections.Generic; namespace X.WinForms.Controls { /// <summary> /// 标题:TreeView 的勾选模式 /// </summary> public enum TreeViewCheckMode { /// <summary> /// 默认(保留) /// </summary> Default = -1, /// <summary> /// 无法选择 /// </summary> None = 0, /// <summary> /// 只能选择一项。 /// </summary> One = 1, /// <summary> /// 可以选择多项。 /// </summary> Multi = 2, } public enum DefaultBoolean { False = 0, True = 1, Default = 2 } /// <summary> /// 标题:多选上级节点的模式 /// </summary> public enum TreeViewParentCheckMode { AnyCheck, AllCheckOnSameLevel } /// <summary> /// 多选选项 /// </summary> public class TreeViewMutiCheckOptions { private DefaultBoolean fAllowCheckParent = DefaultBoolean.True; private TreeViewParentCheckMode fCheckParentMode = TreeViewParentCheckMode.AnyCheck; private DefaultBoolean fAllowCheckChild = DefaultBoolean.True; /// <summary> /// 获取或设置一个值,它表示是否选中上级节点。 /// </summary> public DefaultBoolean AllowCheckParent { get { return fAllowCheckParent; } set { fAllowCheckParent = value; } } /// <summary> /// 获取或设置一个值,它表示选中上级节点的模式。 /// </summary> public TreeViewParentCheckMode CheckParentMode { get { return fCheckParentMode; } set { fCheckParentMode = value; } } /// <summary> /// 获取或设置一个值,它表示是否选中子节点。 /// </summary> public DefaultBoolean AllowCheckChild { get { return fAllowCheckChild; } set { fAllowCheckChild = value; } } public TreeViewMutiCheckOptions(DefaultBoolean fAllowCheckParent, TreeViewParentCheckMode fCheckParentMode, DefaultBoolean fAllowCheckChild) { this.fAllowCheckParent = fAllowCheckParent; this.fCheckParentMode = fCheckParentMode; this.fAllowCheckChild = fAllowCheckChild; } } /// <summary> /// 标题:TreeView 控件扩展 /// 描述:2010-02-28 增加几种 CheckBox 的勾选模式。 /// 1 “单选” /// 2 “多选子节点” /// 3 “勾选任意节点同中父节点” /// 4 “勾选同级节点中的所有节点同进返回中父节点” /// </summary> public class TreeViewEx : TreeView { protected SysAction SysAction = new SysAction(); private TreeViewCheckMode fCheckMode; private TreeViewMutiCheckOptions fMutiCheckOptions; /// <summary> /// 获取或设置一个值,它表示当前 TreeView 的勾选模式。 /// </summary> public virtual TreeViewCheckMode CheckMode { get { return fCheckMode; } set { fCheckMode = value; } } /// <summary> /// 获取或设置一个值,它表示多选模式下的选项。 /// </summary> public TreeViewMutiCheckOptions MutiCheckOptions { get { if (this.fMutiCheckOptions == null) this.fMutiCheckOptions = new TreeViewMutiCheckOptions(DefaultBoolean.True, TreeViewParentCheckMode.AnyCheck, DefaultBoolean.True); return this.fMutiCheckOptions; } set { fMutiCheckOptions = value; } } /// <summary> /// 获取 TreeView 所有节点 /// </summary> public List<TreeNode> AllNodes { get { List<TreeNode> array = new List<TreeNode>(); foreach (TreeNode node in this.Nodes) { array.Add(node); GetAllNodes(array, node); } return array; } } private void GetAllNodes(List<TreeNode> array, TreeNode parentNode) { foreach (TreeNode node in parentNode.Nodes) { array.Add(node); GetAllNodes(array, node); } } protected override void OnBeforeCheck(TreeViewCancelEventArgs e) { if (!this.SysAction.Running) { if (this.CheckMode == TreeViewCheckMode.None) { e.Cancel = true; } else if (this.CheckMode == TreeViewCheckMode.Multi) { if (this.MutiCheckOptions.AllowCheckParent == DefaultBoolean.True) { if (this.MutiCheckOptions.CheckParentMode == TreeViewParentCheckMode.AnyCheck) { // 如果子节点有选中项,则不能取消选择。 bool hasCheckOne = false; foreach (TreeNode node in e.Node.Nodes) { if (node.Checked) { hasCheckOne = true; break; } } if (hasCheckOne) { e.Cancel = true; } } } } } base.OnBeforeCheck(e); } protected override void OnAfterCheck(TreeViewEventArgs e) { if (this.CheckMode == TreeViewCheckMode.One) { this.CheckAllNode(new List<TreeNode>(new TreeNode[] { e.Node }), false); } else if (this.CheckMode == TreeViewCheckMode.Multi) { if (this.MutiCheckOptions.AllowCheckChild == DefaultBoolean.True) { this.CheckAllNode(e.Node, new List<TreeNode>(new TreeNode[] { e.Node }), e.Node.Checked); } if (this.MutiCheckOptions.AllowCheckParent == DefaultBoolean.True) { if (!this.SysAction.Running) { DefaultBoolean allowCheckChild = this.MutiCheckOptions.AllowCheckChild; try { this.MutiCheckOptions.AllowCheckChild = DefaultBoolean.False; this.CheckParent(e.Node, this.MutiCheckOptions.CheckParentMode); } finally { this.MutiCheckOptions.AllowCheckChild = allowCheckChild; } } } } base.OnAfterCheck(e); } public virtual void CheckAllNode(bool checkedValue) { this.CheckAllNode(null, checkedValue); } public virtual void CheckAllNode(List<TreeNode> excludeNodes, bool checkedValue) { this.CheckAllNode(null, excludeNodes, checkedValue); } /// <summary> /// 设置某个节点及它的所有子节点的选中状态,当 parentNode 为 Null 时表示根节点。 /// </summary> /// <param name="parentNode">需要设置的节点</param> /// <param name="excludeNodes">排除不处理的节点</param> /// <param name="checkedValue">选中状态</param> public virtual void CheckAllNode(TreeNode parentNode, List<TreeNode> excludeNodes, bool checkedValue) { if (parentNode != null && parentNode.Checked != checkedValue) { if (excludeNodes != null && !excludeNodes.Contains(parentNode)) this.TrySafeSetCheckValue(parentNode, checkedValue); } TreeNodeCollection nodes = (parentNode == null) ? this.Nodes : parentNode.Nodes; foreach (TreeNode node in nodes) this.CheckAllNode(node, excludeNodes, checkedValue); } public void CheckParent(TreeNode checkedNode, TreeViewParentCheckMode mode) { TreeNode parentNode = checkedNode.Parent; if (parentNode == null) return; if (mode == TreeViewParentCheckMode.AnyCheck) { bool checkedValue = false; // 若同一级都没有选择,同时取消父节点的选择。 foreach (TreeNode node in parentNode.Nodes) { if (node.Checked) { checkedValue = true; break; } } this.TrySafeSetCheckValue(parentNode, checkedValue); this.CheckParent(parentNode, mode); } else if (mode == TreeViewParentCheckMode.AllCheckOnSameLevel) { bool checkedValue = true; foreach (TreeNode node in parentNode.Nodes) { if (!node.Checked) { checkedValue = false; break; } } this.TrySafeSetCheckValue(parentNode, checkedValue); this.CheckParent(parentNode, mode); } } public void TrySafeSetCheckValue(TreeNode node, bool checkedValue) { if (node == null) return; try { this.SysAction.Begin(); if (node.Checked != checkedValue) node.Checked = checkedValue; } finally { this.SysAction.End(); } } } public class SysAction { private bool fRunning = false; public bool Running { get { return fRunning; } } public void Begin() { this.fRunning = true; } public void End() { this.fRunning = false; } } } 使用: this.treeView1.CheckMode = X.WinForms.Controls.TreeViewCheckMode.Multi; this.treeView1.MutiCheckOptions.AllowCheckParent = DefaultBoolean.True; this.treeView1.MutiCheckOptions.AllowCheckChild = DefaultBoolean.True; this.treeView1.MutiCheckOptions.CheckParentMode = TreeViewParentCheckMode.AllCheckOnSameLevel;
转自:https://social.msdn.microsoft.com/Forums/zh-CN/d0d60151-f433-4ba2-abe5-e4524885208f/treeview?forum=visualcshartzhchs