目的:将树形节点封装成带有泛型和事件的方法,易于操作
一、封装的节点类型
带有鼠标左键单击的节点
/// <summary> 泛型节点 </summary> public class TreeNodeClick : TreeNode { public TreeNodeClick() { this.OnClickEvent = l => { // Todo :如果当前没有注册 默认勾选子节点第一个 var cNode = this.FindAll<TreeNodeClick>(); if (cNode != null && cNode.Count > 1) { cNode[1].OnClickEvent(cNode[1]); } }; } /// <summary> 节点的行为 </summary> public Action<TreeNodeClick> OnClickEvent; }
带有鼠标右键单击的节点
/// <summary> 右键点击行为 </summary> public class TreeNodeRightClick : TreeNodeClick { /// <summary> 节点的行为 </summary> public Action<TreeNodeRightClick> OnRightClickEvent; /// <summary> 节点的行为 </summary> public Action<TreeNodeRightClick> OnDeleteClickEvent; }
支持协变的节点接口(用于协变泛型查找)
/// <summary> 支持泛型协变接口(用来筛选指定指定T类型的继承关系) </summary> public interface ITreeNodeInterface<out T> { /// <summary> 协变泛型值 </summary> T TGetParam { get; } }
带有泛型的左键点击节点
/// <summary> 泛型节点 </summary> public class TreeNodeClick<T> : TreeNodeClick, ITreeNodeInterface<T> { /// <summary> 节点的泛型参数 </summary> public T Param; /// <summary> 协变泛型参数 </summary> public T TGetParam { get { return Param; } } }
带有泛型的右键点击节点
/// <summary> 右键点击行为 </summary> public class TreeNodeRightClick<T> : TreeNodeRightClick, ITreeNodeInterface<T> { // 节点的泛型参数 public T Param; /// <summary> 节点的行为 </summary> public Action<TreeNodeRightClick<T>> OnTRightClickEvent; /// <summary> 节点的行为 </summary> public Action<TreeNodeRightClick<T>> OnTDeleteClickEvent; public T TGetParam { get { return Param; } } }
多个泛型关联的节点
/// <summary> 右键点击行为 </summary> public class TreeNodeRightClick<T, V> : TreeNodeRightClick { /// <summary> 数据 </summary> public T Param; /// <summary> 关联 </summary> public V Connect;
带有是否选择的节点
/// <summary> 泛型节点 </summary> public class TreeNodeSingleCheck : TreeNodeClick { /// <summary> 是否被选中 </summary> public bool IsChoose = false; /// <summary> 节点的行为 </summary> public Action<TreeNodeSingleCheck> OnSaveEvent; /// <summary> 节点的行为 </summary> public Action<TreeNodeSingleCheck> OnChooseEvent; }
数值模拟定制的节点(仅供参考)
/// <summary> 双重介质节点 </summary> public class TreeNodeDoubleParam<T> : TreeNodeRightClick<T> { DoubleType _doubleType; // HTodo :基质节点 TreeNodeRightClick<GridTable> _jzTn; // HTodo :裂缝节点 TreeNodeRightClick<GridTable> _lfTn; /// <summary> 根据类型加载节点 </summary> public void LoadDoubleNode(DoubleType doubleType) { _doubleType = doubleType; // 单孔 if (doubleType == DoubleType.DKJZMX) { return; } // 双孔 _jzTn = new TreeNodeRightClick<GridTable>(); _jzTn.Name = "jz"; _jzTn.Text = "裂缝"; this.Nodes.Add(_jzTn); _lfTn = new TreeNodeRightClick<GridTable>(); _lfTn.Name = "lf"; _lfTn.Text = "基质"; this.Nodes.Add(_lfTn); } /// <summary> 根据索引插入节点 </summary> public void AddDoubleNode(int totalCount, int index, TreeNodeRightClick<GridTable> tn) { // 单孔 if (_doubleType == DoubleType.DKJZMX) { this.Nodes.Add(tn); return; } // 双孔 总数必须是偶数 不以双重介质为主节点 if (totalCount % 2 == 0) { if (totalCount / 2 < index) { tn.Text = (index - totalCount / 2).ToString(); _lfTn.Param = tn.Param; _lfTn.Nodes.Add(tn); } else { _jzTn.Param = tn.Param; _jzTn.Nodes.Add(tn); } } } }
二、注册和触发泛型和事件节点的方法
扫描二维码关注公众号,回复:
1576151 查看本文章
this.treeView.NodeMouseClick += new TreeNodeMouseClickEventHandler(treeView_NodeMouseClick);
/// <summary> 节点单击事件 </summary> void treeView_NodeMouseClick(object sender, TreeNodeMouseClickEventArgs e) { TreeNode pNode = e.Node; if (e.Button == MouseButtons.Left) { if (pNode is TreeNodeClick) { TreeNodeClick Tex = pNode as TreeNodeClick; SelectNode = Tex; if (Tex.OnClickEvent != null) { this.HideAllWindows(); Tex.OnClickEvent.Invoke(Tex); } } } if (e.Button == MouseButtons.Right) { if (pNode is TreeNodeRightClick<int>) { TreeNodeRightClick<int> Tex = pNode as TreeNodeRightClick<int>; if (Tex.OnRightClickEvent != null) { Tex.OnRightClickEvent.Invoke(Tex); } } } }
三、节点的泛型查找扩展方法
/// <summary> winform treeview的扩展方法 </summary> public static class TreeViewEx { /// <summary> 遍历所有节点 执行操作方法 </summary> public static void Foreach(this TreeView treeView, Action<TreeNode> match) { var tns = treeView.Nodes; foreach (TreeNode tn in tns) { tn.Foreach(match); } } /// <summary> 遍历所有节点 执行操作方法 </summary> public static void Foreach(this TreeNode treeNode, Action<TreeNode> match) { // 执行方法 match(treeNode); if (treeNode.Nodes.Count > 0) { // 遍历节点 foreach (TreeNode tn in treeNode.Nodes) { tn.Foreach(match); } } } /// <summary> 查找所有满足条件的节点 </summary> public static List<T> FindAll<T>(this TreeView treeView, Predicate<TreeNode> match) where T : class { List<T> find = new List<T>(); var tns = treeView.Nodes; foreach (TreeNode tn in tns) { tn.FindAll<T>(match, ref find); } return find; } /// <summary> 查找所有满足条件的节点 </summary> public static void FindAll<T>(this TreeNode treeNode, Predicate<TreeNode> match, ref List<T> find) where T:class { if (treeNode == null) return; // 执行方法 bool isMatch = match(treeNode); if (isMatch && treeNode is T) { find.Add(treeNode as T); } if (treeNode.Nodes.Count > 0) { // 遍历节点 foreach (TreeNode tn in treeNode.Nodes) { tn.FindAll<T>(match, ref find); } } } public static List<T> FindAll<T>(this TreeView treeView) where T:class { return treeView.FindAll<T>(l => true); } public static List<T> FindAll<T>(this TreeNode treeNode) where T : class { List<T> ts = new List<T>(); treeNode.FindAll<T>(l => true, ref ts); return ts; } public static List<T> FindAll<T>(this TreeNode treeNode, Predicate<TreeNode> match) where T : class { List<T> ts = new List<T>(); treeNode.FindAll<T>(match, ref ts); return ts; } /// <summary> 在本节点下查找指定节点 </summary> public static List<T> FindChild<T>(this TreeNode treeNode, Predicate<TreeNode> match) where T : class { List<T> find = new List<T>(); foreach (TreeNode tn in treeNode.Nodes) { // 执行方法 bool isMatch = match(tn); if (isMatch && tn is T) { find.Add(tn as T); } } return find; } /// <summary> 清空指定节点节点 </summary> public static void ClearNodes(this TreeNode treeNode, Predicate<TreeNode> match) { List<TreeNode> temp = new List<TreeNode>(); foreach (TreeNode tn in treeNode.Nodes) { if (match(tn)) { temp.Add(tn); } } foreach (var v in temp) { treeNode.Nodes.Remove(v); } } /// <summary> 清空指定节点节点 </summary> public static void ClearNodes(this TreeView tree, Predicate<TreeNode> match) { List<TreeNode> temp = new List<TreeNode>(); foreach (TreeNode tn in tree.Nodes) { if (match(tn)) { temp.Add(tn); } } foreach (var v in temp) { tree.Nodes.Remove(v); } } /// <summary> 清空除匹配以为的节点 </summary> public static void ClearWithOutNodes(this TreeView tree, Predicate<TreeNode> match) { List<TreeNode> temp = new List<TreeNode>(); foreach (TreeNode tn in tree.Nodes) { if (!match(tn)) { temp.Add(tn); } } foreach (var v in temp) { tree.Nodes.Remove(v); } } /// <summary> 对当前子节点执行指定操作</summary> public static void ForeachChildNode(this TreeNode treeNode, Action<TreeNode> act) { List<TreeNode> temp = new List<TreeNode>(); foreach (TreeNode tn in treeNode.Nodes) { act(tn); } } }
四、泛型查找应用示例:
List<TreeNodeClick<PVTW>> pvtws = this.treeView.FindAll<TreeNodeClick<PVTW>>();
foreach (TreeNodeClick<PVTW> v in pvtws)
{
// 将每个分区添加泡点露点类型
_props.Add(v.Param);
}
五、应用逆变协变查找泛型节点示例:
var items = this.treeView.FindAll<ITreeNodeInterface<TableKey>>();
说明:TableKey是很多节点类似 节点TreeNodeClick<PVTW>中PVTW的抽象类
六、应用示例:
加载树形:
/// <summary> 刷新底层属性节点 </summary> void RefreshPropertyNode() { int x = DefineModelSZConfiger.InstanceByName(this._ecl.ID).X; int y = DefineModelSZConfiger.InstanceByName(this._ecl.ID).Y; int z = DefineModelSZConfiger.InstanceByName(this._ecl.ID).Z; // 净毛比 if (GeoModelDataConfiger.InstanceByName(this._ecl.ID).IsUseNTG) { #region - 净毛比 - TreeNodeDoubleParam<NTG> dataNTG = new TreeNodeDoubleParam<NTG>(); NTG ntg = _grid.CreateSingle<NTG>("NTG"); ntg.Build(z, x, y); //dataNTG.LoadDoubleNode(DefineModelSZConfiger.InstanceByName(this._ecl.ID).DoubleType); foreach (var t in ntg.Tables) { TreeNodeRightClick<GridTable> tbn = new TreeNodeRightClick<GridTable>(); tbn.Name = t.IndexNum.ToString(); tbn.Text = t.IndexNum.ToString(); tbn.Param = t; dataNTG.AddDoubleNode(ntg.Tables.Count, t.IndexNum, tbn); tbn.OnClickEvent = l => { this.HideWindow(arrayGridCapsule, false); this.ActiveWindow(arrayGridCapsule); this.gridLineArrayGrid.BindGridTable(ntg.Tables[t.IndexNum - 1]); this.gridLineArrayGrid.BindTableUnit(UnitService.InstanceByName(this._ecl.ID).RatioUnit); this.gridLineArrayGrid.RefreshGridForm(); this.gridLineArrayGrid.RefreshData(); }; } dataNTG.Name = Guid.NewGuid().ToString(); dataNTG.Text = "净毛比".PadRight(ProModelDataConfiger.Instance.NameLengh); this.treeView.Nodes.Add(dataNTG); dataNTG.Param = ntg; #endregion } #region - 净厚度 - TreeNodeDoubleParam<DZNET> dataDZNET = new TreeNodeDoubleParam<DZNET>(); DZNET dznet = _grid.CreateSingle<DZNET>("DZNET"); dznet.Build(z, x, y); dataDZNET.LoadDoubleNode(DefineModelSZConfiger.InstanceByName(this._ecl.ID).DoubleType); foreach (var t in dznet.Tables) { TreeNodeRightClick<GridTable> tbn = new TreeNodeRightClick<GridTable>(); tbn.Name = t.IndexNum.ToString(); tbn.Text = t.IndexNum.ToString(); tbn.Param = t; dataDZNET.AddDoubleNode(dznet.Tables.Count, t.IndexNum, tbn); tbn.OnClickEvent = l => { this.HideWindow(arrayGridCapsule, false); this.ActiveWindow(arrayGridCapsule); this.gridLineArrayGrid.BindGridTable(dznet.Tables[t.IndexNum - 1]); this.gridLineArrayGrid.BindTableUnit(UnitService.InstanceByName(this._ecl.ID).RatioUnit); this.gridLineArrayGrid.RefreshGridForm(); this.gridLineArrayGrid.RefreshData(); }; } dataDZNET.Name = Guid.NewGuid().ToString(); dataDZNET.Text = "净厚度".PadRight(ProModelDataConfiger.Instance.NameLengh); this.treeView.Nodes.Add(dataDZNET); dataDZNET.Param = dznet; #endregion } }
保存数据:
#region - 保存 - /// <summary> 保存 </summary> public void Save() { var ntg = this.treeView.FindAll<TreeNodeRightClick<NTG>>(); if (ntg != null && ntg.Count > 0) { // 将每个分区添加泡点露点类型 _grid.Add(ntg[0].Param); } var dznet = this.treeView.FindAll<TreeNodeRightClick<DZNET>>(); if (dznet != null && dznet.Count > 0) { // 将每个分区添加泡点露点类型 _grid.Add(dznet[0].Param); } var poro = this.treeView.FindAll<TreeNodeRightClick<PORO>>(); if (poro != null && poro.Count > 0) { // 将每个分区添加泡点露点类型 _grid.Add(poro[0].Param); } } #endregion