当前位置: 首页 > news >正文

C#将【程序集引用-依赖关系】展示到NetronLight图表中

C#将【程序集引用-依赖关系】展示到NetronLight图表中

修改NetronLight.SimpleRectangle的Paint事件 将文本居中。

		public override void Paint(System.Drawing.Graphics g){g.FillRectangle(shapeBrush,rectangle);if(hovered || isSelected)g.DrawRectangle(new Pen(Color.Red,2F),rectangle);elseg.DrawRectangle(blackPen,rectangle);for(int k=0;k<connectors.Count;k++){connectors[k].Paint(g);}//well, a lot should be said here like//the fact that one should measure the text before drawing it,//resize the width and height if the text if bigger than the rectangle,//alignment can be set and changes the drawing as well...//here we keep it really simple:if (text != string.Empty){//修改文本居中对齐SizeF size = g.MeasureString(text, font, 500, StringFormat.GenericTypographic);float offsetX = rectangle.Width > size.Width ? (rectangle.Width - size.Width) / 2 : 0;float offsetY = rectangle.Height > size.Height ? (rectangle.Height - size.Height) / 2 : 0;g.DrawString(text, font, Brushes.Black, rectangle.X + offsetX, rectangle.Y + offsetY);//g.DrawString(text, font, Brushes.Black, rectangle.X + 10, rectangle.Y + 10);}}

新建窗体FormShowAssemblyDependent

窗体设计器代码如下:

FormShowAssemblyDependent.Designer.cs文件


namespace ShowTreeNodeToDiagram
{partial class FormShowAssemblyDependent{/// <summary>/// Required designer variable./// </summary>private System.ComponentModel.IContainer components = null;/// <summary>/// Clean up any resources being used./// </summary>/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>protected override void Dispose(bool disposing){if (disposing && (components != null)){components.Dispose();}base.Dispose(disposing);}#region Windows Form Designer generated code/// <summary>/// Required method for Designer support - do not modify/// the contents of this method with the code editor./// </summary>private void InitializeComponent(){this.btnShowDiagram = new System.Windows.Forms.Button();this.graphControl1 = new NetronLight.GraphControl();this.tvAssembly = new System.Windows.Forms.TreeView();this.SuspendLayout();// // btnShowDiagram// this.btnShowDiagram.Font = new System.Drawing.Font("宋体", 12F);this.btnShowDiagram.Location = new System.Drawing.Point(39, 7);this.btnShowDiagram.Name = "btnShowDiagram";this.btnShowDiagram.Size = new System.Drawing.Size(158, 26);this.btnShowDiagram.TabIndex = 5;this.btnShowDiagram.Text = "展示树节点到图表";this.btnShowDiagram.UseVisualStyleBackColor = true;this.btnShowDiagram.Click += new System.EventHandler(this.btnShowDiagram_Click);// // graphControl1// this.graphControl1.Location = new System.Drawing.Point(290, 5);this.graphControl1.Name = "graphControl1";this.graphControl1.ShowGrid = true;this.graphControl1.Size = new System.Drawing.Size(1421, 600);this.graphControl1.TabIndex = 4;this.graphControl1.Text = "graphControl1";// // tvAssembly// this.tvAssembly.Location = new System.Drawing.Point(4, 42);this.tvAssembly.Name = "tvAssembly";this.tvAssembly.Size = new System.Drawing.Size(280, 563);this.tvAssembly.TabIndex = 3;// // FormShowAssemblyDependent// this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;this.ClientSize = new System.Drawing.Size(1723, 611);this.Controls.Add(this.btnShowDiagram);this.Controls.Add(this.graphControl1);this.Controls.Add(this.tvAssembly);this.Name = "FormShowAssemblyDependent";this.Text = "显示程序集依赖";this.Load += new System.EventHandler(this.FormShowAssemblyDependent_Load);this.ResumeLayout(false);}#endregionprivate System.Windows.Forms.Button btnShowDiagram;private NetronLight.GraphControl graphControl1;private System.Windows.Forms.TreeView tvAssembly;}
}

FormShowAssemblyDependent实现代码如下

FormShowAssemblyDependent.cs文件

using NetronLight;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;namespace ShowTreeNodeToDiagram
{public partial class FormShowAssemblyDependent : Form{public FormShowAssemblyDependent(){InitializeComponent();}private void FormShowAssemblyDependent_Load(object sender, EventArgs e){//string fileName = @"D:\Debug\XX.exe";//Assembly assembly = Assembly.LoadFile(fileName);Assembly assembly = Assembly.GetEntryAssembly();MessageBox.Show(assembly.GetName().Name+"\n处理器结构:"+ assembly.GetName().ProcessorArchitecture+"\n类型:"+ assembly.GetType()+"\n程序集位置:"+ assembly.CodeBase);TreeNode rootNode = new TreeNode(assembly.GetName().Name);tvAssembly.Nodes.Add(rootNode);GetAssemblies(assembly, rootNode);tvAssembly.ExpandAll();}/// <summary>/// 递归获取引用的程序集信息/// </summary>/// <param name="assembly"></param>/// <param name="treeNode"></param>private void GetAssemblies(Assembly assembly, TreeNode treeNode) {Queue<Tuple<Assembly, TreeNode>> queue = new Queue<Tuple<Assembly, TreeNode>>();HashSet<Assembly> loadedAssemblies = new HashSet<Assembly>();queue.Enqueue(Tuple.Create(assembly, treeNode));treeNode.Tag = assembly;//节点的数据对象是一个Assemblywhile (queue.Any()){Tuple<Assembly, TreeNode> tuple = queue.Dequeue();AssemblyName[] assemblyNames = tuple.Item1.GetReferencedAssemblies();for (int i = 0; i < assemblyNames.Length; i++){Assembly reference = Assembly.Load(assemblyNames[i]);TreeNode referenceNode = new TreeNode(reference.GetName().Name);referenceNode.Tag = reference;//节点的数据对象是一个Assemblytuple.Item2.Nodes.Add(referenceNode);if (!loadedAssemblies.Contains(reference)) //loadedAssemblies.Contains(reference.FullName){loadedAssemblies.Add(reference);//tuple.Item2.Nodes.Add(referenceNode);queue.Enqueue(Tuple.Create(reference, referenceNode));}}}//MessageBox.Show(string.Join(",\n", loadedAssemblies.Select(x => x.GetName().Name)));}/// <summary>/// 程序集A是否引用程序集B/// </summary>/// <param name="A"></param>/// <param name="B"></param>/// <returns></returns>private bool IsReferencedAssembly(Assembly A, Assembly B) {AssemblyName[] assemblyNames = A.GetReferencedAssemblies();int index = Array.FindIndex(assemblyNames, x => x.Name == B.GetName().Name);return A != null && B != null && index >= 0;}/// <summary>/// 获取树节点的最大深度Level/// </summary>/// <param name="treeNode"></param>/// <returns></returns>private int GetMaxLevel(TreeNode treeNode){//考虑到节点可能重复,这里遍历所有节点,找出所有的节点深度HashSet<int> levelCollection = new HashSet<int>();Stack<TreeNode> nodes = new Stack<TreeNode>();nodes.Push(treeNode);while (nodes.Count > 0){TreeNode currentNode = nodes.Pop();levelCollection.Add(currentNode.Level);for (int i = 0; i < currentNode.Nodes.Count; i++){nodes.Push(currentNode.Nodes[i]);}}return levelCollection.Max();}/// <summary>/// 查找指定深度的所有节点集合。获取指定深度的节点集合。这些节点的属于同一行号【Y坐标一致】/// </summary>/// <param name="rootNode"></param>/// <param name="level"></param>/// <returns></returns>private List<TreeNode> GetCurrentLevelNodes(TreeNode rootNode, int level){List<TreeNode> nodeList = new List<TreeNode>();if (rootNode.Level == level){nodeList.Add(rootNode);}for (int i = 0; i < rootNode.Nodes.Count; i++){TreeNode current = rootNode.Nodes[i];//如果当前节点的深度 不等于 已知深度,就继续递归。当前节点的深度 等于 已知深度,就添加该节点if (current.Level == level){nodeList.Add(current);}else{List<TreeNode> tempList = GetCurrentLevelNodes(current, level);if (tempList.Count > 0){nodeList.AddRange(tempList);}}}return nodeList;}/// <summary>/// 查找指定深度的所有节点集合【去除重复的节点:函数名一致的只保留一个】。获取指定深度的节点集合,这些节点的属于同一行号【Y坐标一致】/// 节点已经存在ShapeBase的也必须移除掉/// </summary>/// <param name="rootNode"></param>/// <param name="level"></param>/// <returns></returns>private List<TreeNode> GetDistinctLevelNodes(TreeNode rootNode, int level){List<TreeNode> nodeList = GetCurrentLevelNodes(rootNode, level);HashSet<string> methodNames = new HashSet<string>();for (int i = 0; i < nodeList.Count; i++){//如果重复,就移除掉当前元素if (!methodNames.Add(nodeList[i].Text)){nodeList.RemoveAt(i);i--;}}//节点已经存在ShapeBase的也不能访问了for (int i = 0; i < nodeList.Count; i++){//如果重复,就移除掉当前元素if (GetShapeByTreeNode(nodeList[i]) != null){nodeList.RemoveAt(i);i--;}}return nodeList;}/// <summary>/// 通过树节点来获取对应的形状节点/// </summary>/// <param name="treeNode"></param>/// <returns></returns>private ShapeBase GetShapeByTreeNode(TreeNode treeNode){SimpleRectangle shapeNode = graphControl1.Shapes.Cast<SimpleRectangle>().ToList().Find(x => x.Text == treeNode.Text);return shapeNode;}/// <summary>/// 父子节点进行连线:连线端点Bottom, Left, Right, Top。由起始节点的底部端点 连接到 终止节点的顶部端点/// </summary>/// <param name="fromNode"></param>/// <param name="toNode"></param>private void AddLink(TreeNode fromNode, TreeNode toNode){ShapeBase fromShape = GetShapeByTreeNode(fromNode);ShapeBase toShape = GetShapeByTreeNode(toNode);Assembly A = fromNode.Tag as Assembly;Assembly B = toNode.Tag as Assembly;if (fromShape != null && toShape != null && IsReferencedAssembly(A, B)){//连线端点Bottom, Left, Right, Top。由起始节点的底部端点 连接到 终止节点的顶部端点graphControl1.AddConnection(fromShape.Connectors[0], toShape.Connectors[3]);}}/// <summary>/// 生成一个形状节点/// </summary>/// <param name="treeNode"></param>/// <param name="point"></param>private void GenerateShapeNode(TreeNode treeNode, Point point, int width){SimpleRectangle diagramNode = new SimpleRectangle(graphControl1);diagramNode.Text = treeNode.Text;//主程序提示 特殊处理diagramNode.Width = width;diagramNode.Height = 30;diagramNode.Location = point;diagramNode.ShapeColor = Color.GreenYellow;if (!graphControl1.Shapes.Cast<SimpleRectangle>().Any(x => x.Text == treeNode.Text)){graphControl1.Shapes.Add(diagramNode);}}/// <summary>/// 生成节点之间的连线/// </summary>private void GenerateLinks(TreeNode treeNode){Stack<TreeNode> nodes = new Stack<TreeNode>();nodes.Push(treeNode);while (nodes.Count > 0){TreeNode fromNode = nodes.Pop();for (int i = 0; i < fromNode.Nodes.Count; i++){TreeNode toNode = fromNode.Nodes[i];AddLink(fromNode, toNode);nodes.Push(toNode);//将当前子节点插入集合中,继续连线}}}private void btnShowDiagram_Click(object sender, EventArgs e){graphControl1.Connections.Clear();//清除所有连线graphControl1.Shapes.Clear();////清除所有形状节点//根节点是第一个TreeNode rootNode = tvAssembly.Nodes[0];int maxLevel = GetMaxLevel(rootNode);//获取树节点的最大深度//按照节点的深度Level将树节点进行分组for (int level = 0; level <= maxLevel; level++){List<TreeNode> nodeList = GetDistinctLevelNodes(rootNode, level);int sumWidth = nodeList.Sum(x => GetApplyWidth(60, x.Text, graphControl1.Font));//节点所占用的宽度集合int offsetX = (graphControl1.Width - sumWidth) / (nodeList.Count + 1);int usedWidth = 0;for (int i = 0; i < nodeList.Count; i++){int width = GetApplyWidth(60, nodeList[i].Text, graphControl1.Font);GenerateShapeNode(nodeList[i], new Point(3 + offsetX * (i + 1) + usedWidth, 20 + 120 * level), width + 50);usedWidth += width;}                }//生成节点之间的连线GenerateLinks(rootNode);//获取指定深度的节点集合。这些节点的属于同一行号【Y坐标一致】graphControl1.Invalidate();}/// <summary>/// 获取节点的宽度:考虑到有些节点的文本过长,当文本width大于150时,进行特殊处理/// </summary>/// <param name="widthDefault"></param>/// <param name="text"></param>/// <param name="font"></param>/// <returns></returns>private int GetApplyWidth(int widthDefault, string text, Font font){//获得准确的字符串宽度:Graphics g = this.CreateGraphics();//一个英文字符占用6个像素//MeasureString(int width)参数width=350: 允许测量字符串的最大宽度(待测量的字符串长度如果>350,也返回350)int actualWidth = (int)g.MeasureString(text, font, 350, StringFormat.GenericTypographic).Width;//Console.WriteLine($"字符个数【{text.Length}】,测量长度【{actualWidth}】,字符串【{text}】,文本格式【{font}】");return Math.Max(widthDefault, actualWidth);}}
}

运行如图:

 

http://www.xdnf.cn/news/1144261.html

相关文章:

  • Java 核心工具类 API 详解(一):从 Math 到 Runtime 的实用指南
  • 设计模式五:桥模式(Bridge Pattern)
  • wedo牛-----第47节(免费分享图纸)
  • MBIST - Memory BIST会对memory进行清零吗?
  • 基于单片机的便携太阳能光伏系统研究
  • C语言—如何生成随机数+原理详细分析
  • 20250718-FDU-HDUOJ钉耙编程一
  • 初探:C语言FILE结构之文件描述符与缓冲区的实现原理
  • 更适合后端宝宝的前端三件套之HTML
  • CentOS7 内网服务器yum修改
  • 有好内容,如何做好知识变现?
  • 【Zephyr开发实践系列】08_NVS文件系统调试记录
  • GEV/POT/Markov/点过程/贝叶斯极值全解析;基于R语言的极值统计学
  • 【案例教程】基于现代R语言【Tidyverse、Tidymodel】的机器学习方法与案例分析实践技术应用
  • [AI8051U入门第五步]modbus_RTU主机
  • stack and queue 之牛刀小试
  • Excel批量生成SQL语句 Excel批量生成SQL脚本 Excel拼接sql
  • 大型市政污水处理厂“智变”记:天拓四方IOT平台让磁悬浮鼓风机“活”起来
  • React 实现人员列表多选、全选与取消全选功能
  • MC0457符咒封印
  • Ansible + Shell 服务器巡检脚本
  • mysql not in 查询引发的bug问题记录
  • pycharm结构查看器
  • 2.3 前端-ts的接口以及自定义类型
  • 哪个厂家生产的戒烟药好:从机制到体验的差异化博弈
  • MySQL 插入时间 更新时间
  • 推荐 1 款 4.5k stars 的AI 大模型驱动的开源知识库搭建系统
  • 跨域问题及解决方案
  • AI(day10)模块化编程概念(模块、包、导入)及常见系统模块总结和第三方模块管理
  • Java Web项目Dump文件分析指南