目的:将树形节点封装成带有泛型和事件的方法,易于操作
一、封装的节点类型
带有鼠标左键单击的节点
/// <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);
}
}
}
}
二、注册和触发泛型和事件节点的方法
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