☰
EPLAN API开发实战:用C#插件批量修改电气图纸
2026/10/7 3:37:19 网站建设 项目流程

简介:面向EPLAN电气设计软件二次开发者的C#插件工程,基于EPLAN API实现自动化与定制化工作流,适合需要批量处理项目、自动生成报告或扩展界面功能的开发场景,无论创建新项目还是改造现有工程都有直接参考价值。资源共137个文件,压缩包仅8.72MB,主要包含动态链接库、C#源代码、可扩展标记语言配置文件与资源文件,另有解决方案和工程文件以及位图和图标素材,目录结构完整,可直接打开编译调试;其中动态链接库是编译产物的主要形式,源代码便于学习与二次修改。包内核心为EPLAN.EplAddin.JMC插件项目,覆盖电气项目管理、图形对象绘制、自定义缩放逻辑等模块,通过阅读源码可以学习如何访问元器件数据、创建电气布局、调整线型颜色字体、处理用户界面事件,还能拓展实现自动计算电流容量、电气规则检查等高级功能。该压缩包保留了缓存和中间文件,便于理解完整构建流程,可作为二次开发的起点模板。目前已有370人学习,适合具备一定C#和电气设计基础、希望深入EPLAN API二次开发的工程师参考。

1. EPLAN API:让电气图纸里的重复劳动变成一段可维护的代码

一个项目上百张图纸、几千个设备元件,下游说型号要换、图框比例要改、部件要统一刷新,这些事逐页去点,不仅耗时间,而且漏改的概率极高。EPLAN API开发就是专门解决这类问题的路子:通过EPLAN开放的托管接口,在.NET里写C#代码,做成eplan项目插件,直接读写项目结构、页、设备、部件和属性,把批量修改和自动出图变成点击一次菜单的事。这篇笔记面向第一次接触EPLAN API的电气工程师、给自动化部门搭工具的中台同事,以及想把EPLAN二次开发能力接进产线系统的设备厂商,按“搭环境→理解对象模型→写可用插件→排坑→进阶”的顺序走一遍。新人能照步骤复现,熟手可以直接跳到第5章的踩坑清单。

2. 搭一个能跑的EPLAN API开发环境:工具链、DLL引用与最小工程

2.1 为什么选C#和.NET Framework,而不是Python或JavaScript

EPLAN API本质上是暴露给.NET的一套托管接口。装上EPLAN之后,安装目录里会有一批Eplan.EplApi开头的程序集(DLL),插件开发就是引用这些DLL,在Visual Studio里写C#,编译成类库,最后放到EPLAN的插件加载目录。为什么官方历史上一直走这条线?因为EPLAN的插件宿主本身就是基于.NET Framework构建的,用C#直接引用程序集就能拿到完整的对象模型,项目、页、设备、部件这些对象都是强类型的,写起来有智能提示,调试也直接。

有人会问:能不能用Python调EPLAN?可以,但通常走的是Automation Interface或Socket接口,那是粗粒度的自动化通道,能实现“启动软件、打开项目、导出数据”,拿不到设备级对象,更没法做交互式的菜单插件。想要“点一下菜单,批量改图纸属性”这种体验,还是得走C#插件。早年间也有人用C++/COM方式做过,纯COM交互的代码量比起C#成倍增加,不值得。

还有一个血泪教训:别用.NET Core/.NET 5+去做EPLAN插件。EPLAN宿主进程加载的是.NET Framework程序集,你新建一个跨平台目标框架,编译出来的程序集运行时大概率不被识别或直接静默失败。老老实实选“.NET Framework 类库”,目标框架按你装的EPLAN版本来,常见是4.6.1到4.8之间,拿不准就选4.7.2,兼容性比较稳。

2.2 引用哪几个核心DLL,输出文件放哪里

打开Visual Studio,新建“类库(.NET Framework)”项目。在项目引用里添加三个核心程序集,它们在EPLAN安装目录下以Eplan.EplApi开头:

程序集主要职责
Eplan.EplApi.ApplicationFramework.dll插件基类、命令解释器、菜单注册、Action调用链
Eplan.EplApi.HEServices.dll项目访问、选择集、对象查找、编辑与保存操作
Eplan.EplApi.Base.dll属性对象、通用工具类、字符串表、线程处理

注意,这三个程序集不要从网上下载,也不要复制到项目目录里。正确做法是在“引用管理器”里直接“浏览”到你本机EPLAN安装目录,选定对应DLL。这样编译时用的是和你当前EPLAN版本匹配的程序集,不会出现接口对不上的情况。EPLAN安装目录一般在系统盘的Program Files下,具体路径看你装的版本,找到包含Eplan.EplApi.*.dll的那个子目录即可。

编译输出要重点检查两件事。第一,平台位数:现在EPLAN大多按x64部署,插件工程要配置成x64,或使用AnyCPU且实际以x64运行;如果错配成x86,EPLAN启动时经常不报错,只是不加载你的插件,排查起来非常像玄学。第二,输出位置:EPLAN加载插件有固定扫描路径,通常在你的用户公共文档目录下的EPLAN子目录里。F5调试时如果EPLAN没带上你的DLL,先去看这个目录里有没有新生成的dll文件,而不是在项目bin目录里瞎找。

2.3 最小工程的入口类:写出第一个能被EPLAN识别的插件

直接上最小可编译代码:

using Eplan.EplApi.ApplicationFramework; namespace EplanApiDemo { public class DemoAddIn : CommandLineAddIn { public override void OnRegister(UserInterface oUI) { // 在EPLAN菜单栏注册一个顶层菜单,挂一个菜单项 MenuManager menu = new MenuManager(); menu.AddMenuItem("项目插件", "EPLAN API:菜单:批量改比例", "", 0, true, true); } } }

逻辑说明:DemoAddIn继承CommandLineAddIn,这是EPLAN插件常见的基类。OnRegister在插件被加载时执行一次,AddMenuItem往EPLAN菜单里塞一项,"EPLAN API:菜单:批量改比例"这个字符串是EPLAN菜单路径格式,冒号分隔层级。最后两个布尔参数控制菜单是否可见、是否置顶显示。

参数说明:第3个参数是Action名,现在传空字符串,表示这个菜单项暂时不绑定任何动作,下一章再把真实命令挂上去。第4个参数0是菜单位置,容易踩坑的是0代表排序最靠前,不同EPLAN版本处理不一致,生产工具建议设大一点或放到自定义菜单组里。编译之前,把项目调试启动方式设为“启动外部程序”,指向Eplan.exe,这样按F5就会带着插件启动。

这段代码本身什么都不干,但它回答了一个插件开发里最常见的问题:“我写了插件为什么EPLAN里没反应?”答案往往不是代码错,而是输出目录不对、平台位数不对、基类没继承对。把这三个变量校正好,EPLAN一打开就能看到菜单项,整个开发链路就算通了。

3. 摸清EPLAN对象模型:项目、页、设备、部件之间的数据路径

3.1 顶层数据结构长什么样:从Project到Function再到Part

EPLAN的数据模型是一棵树:最顶层是Project(项目),往下是页(Page),页上放图框和功能对象(Function,也就是电气图纸里的设备符号),功能对象再关联部件(Part,也就是具体型号物料)。用API操作时,基本路径就是沿着这棵树从上往下找:打开项目,获得到页,从页上拿设备,再改设备的部件或属性。

有一个非常容易混淆的点:设备和部件是两码事。设备(Function)是图纸上的逻辑对象,比如“接触器KM1”;部件(Part)是它关联的具体型号,比如某个品牌的3RT系列接触器。批量改型号改的是Part关联关系,批量改逻辑标识改的是Function属性。动手写代码之前,先想清楚你要改的到底是哪一个,否则属性改错层级,轻则没效果,重则把一张图改乱了。

如果你拿到的EPLAN API.zip包里有类似“drawny2t”这种看起来像个类名或标识的字段,不要急着把它当成代码类名,它很可能只是图纸、绘图相关的样板数据标记。先打开EPLAN项目,看页结构里的页名和Structure是怎么划分的,再映射到API对象,这样能少走半天弯路。

3.2 用SelectionSet和DMObjectsFinder拿到目标对象

EPLAN API里有两条最常用的拿对象路径。SelectionSet负责获取用户当前激活的项目和选中对象;DMObjectsFinder负责在项目内部按类型、名称和属性条件查找对象。看代码:

using Eplan.EplApi.HEServices; public Page[] GetAllPages() { // 通过当前激活项目构造查找器 SelectionSet selection = new SelectionSet(); Project project = selection.Project; // 在项目里枚举所有页 DMObjectsFinder finder = new DMObjectsFinder(project); return finder.GetPages(); }

逻辑说明:第一行SelectionSet并不会真的改变用户的选中状态,它只是读取当前激活项目上下文。DMObjectsFinder拿到项目对象之后,GetPages()把项目所有页枚举出来。这是后续批量操作的基础。

参数说明:GetPages()返回的是全项目的页,包括原理图页、封面页、表格页、布局页。实际处理前先按页类型过滤,否则后面批量改属性时会把不该动的页也改了。过滤一般用Page.PageType或页属性里的类型常量判断。另外,不要在循环里反复new DMObjectsFinder,一是慢,二是反复建立对象访问会产生不必要的内存积累,上千页的大项目性能差距很明显。

3.3 属性读写:Properties对象是唯一的属性入口

EPLAN对象的所有属性都通过Properties类访问,而且属性是用“属性标识”索引的,不是按字符串名字。比如页面比例,在API里对应的往往是某个属性常量,而不是“Scale”字符串。写代码的时候优先用属性常量,不要手写魔法字符串,否则换一个EPLAN版本很容易断掉。

using Eplan.EplApi.Base; using Eplan.EplApi.HEServices; public void SetPageScale(Page page, int scaleValue) { Properties props = page.Properties; // 使用属性常量访问页面比例 props[Properties.Page.PAGE_SCALE] = scaleValue; }

逻辑说明:page.Properties返回该页的属性集合,通过索引器给PAGE_SCALE赋值。赋值后必须调用保存操作,才会写进项目文件。这里要注意Properties的索引器本质上是多维的,上面单参数写法设置的是默认语言的值;如果文档是中英双语,需要追加语言标识符参数,否则只有默认语言被更新。

参数说明:PAGE_SCALE在不同EPLAN版本里保持稳定,但具体取值语义要看你设的比例格式。通常1:2对应数值2,1:4对应数值4。赋值不报错但项目里看不到变化,是新手最爱踩的坑,原因不外乎两个:没调用项目保存,或改了属性后没刷新页面显示缓存。这两个动作记住要成对出现。

using Eplan.EplApi.HEServices; public void SaveAndRefresh(Project project) { project.Save(); project.Refresh(); }

这段是批量修改后的收尾动作:Save()把改动持久化,Refresh()让界面重新加载项目树和页面缓存。注意Save()对大项目很耗时,不要在循环里每改一页就Save一次,而应该全部改完统一保存。

4. 做一个能落地的EPLAN项目插件:从菜单注册到批量改比例的完整实现

4.1 在菜单上挂真实动作:Action注册与回调

上一章入口只有菜单没有动作。要把菜单变成能用按钮,需要走EPLAN的Action机制。CommandLineAddIn里有一个OnAction回调,菜单项通过绑定一个Action名来触发它。完整结构看代码:

using Eplan.EplApi.ApplicationFramework; namespace EplanApiDemo { public class DemoAddIn : CommandLineAddIn { public const string ScaleAction = "EplanApiDemo.ScaleZJ2Action"; public override void OnRegister(UserInterface oUI) { MenuManager menu = new MenuManager(); menu.AddMenuItem("项目插件", "EPLAN API:菜单:批量改比例", ScaleAction, 100, true, true); } public override void OnAction(string actionName) { if (actionName == ScaleAction) { new BatchScale().Run(); // 实际业务逻辑在BatchScale里 } } } }

逻辑说明:AddMenuItem的第三个参数绑定Action名,用户点击菜单后EPLAN调用OnAction并传入这个名字。ScaleAction定义成常量而不是在两处手打字符串,是避免回调比较时拼写不一致。new BatchScale().Run()把菜单动作和业务逻辑解耦,后续加日志、加异常处理都方便。

参数说明:Action名在EPLAN全局最好做到唯一,加项目名前缀是最稳妥的办法。有人觉得裸写“ScaleZJ2”就够了,结果和别的插件撞名,其中一个菜单点击没反应,排查半天才发现是全局重名导致注册被覆盖。position参数这里设成100,比第2章的0要稳,放在菜单靠后的位置,不影响原有菜单顺序。

4.2 批量改页面比例:一个完整的业务类

这个场景呼应标题里“scale”这个标记。真实需求通常是把全项目页面比例统一成某个值,或者是把选中页从1:1批量改成1:2。第2种做法如下:

using Eplan.EplApi.HEServices; using Eplan.EplApi.Base; public class BatchScale { public void Run() { SelectionSet selection = new SelectionSet(); Project project = selection.Project; if (project == null) { return; // 没有打开项目时直接退出 } DMObjectsFinder finder = new DMObjectsFinder(project); Page[] pages = finder.GetPages(); int changed = 0; foreach (Page page in pages) { // 跳过封面、表格、目录页,只处理原理图页 if (!IsSchematicPage(page)) { continue; } Properties props = page.Properties; int oldScale = (int)props[Properties.Page.PAGE_SCALE]; if (oldScale == 2) { continue; } // 已经是目标比例就跳过 props[Properties.Page.PAGE_SCALE] = 2; changed++; } project.Save(); project.Refresh(); } private bool IsSchematicPage(Page page) { // 按页类型常量过滤;不同版本类型编号略有差异 return page.PageType == PageType.Schematic; } }

逻辑说明:循环先过滤页类型,再读旧比例,相同则跳过,不同则赋值,最后统一保存。PageType.Schematic是原理图类型常量,实际项目里还可能包含多层图、宏页,按需求扩展过滤集合。project.Save()放在循环外,避免频繁落盘拖慢整个操作。

参数说明:批量操作要考虑几个边界。第一是页类型过滤,不分类型直接改会把封面和表格页的比例也改了,出图时图框乱套,这是批量翻车的第一大来源。第二是跳过已符合目标值的页,既减少写入量,也让日志里“实际改动多少页”这个数字有参考价值。第三,如果你的项目里有几百张来自宏项目的只读页,赋值可能被拒绝,要在循环里捕获异常并计数,而不是让整个插件崩掉。

4.3 加一个简单的WinForms对话框:把参数交给使用者

命令行式插件只适合作者自己用,交付给别人用时必须有参数界面。最简单的做法是一个WinForms窗体,输入目标比例,点确定后执行批量逻辑。下面只列核心控件部分:

using System.Windows.Forms; public class ScaleDialog : Form { private NumericUpDown scaleInput; public ScaleDialog() { scaleInput = new NumericUpDown { Minimum = 1, Maximum = 100, Value = 2 }; Button okButton = new Button { Text = "开始批量改比例", DialogResult = DialogResult.OK }; Controls.Add(scaleInput); Controls.Add(okButton); } public int GetScale() { return (int)scaleInput.Value; } }

逻辑说明:NumericUpDown把输入限制在数字范围,避免用户填出非法比例。GetScale()在对话框关闭后由外层调用,取用户设定的值传入BatchScale。这个窗体没有直接碰EPLAN API,但它决定了使用体验。

参数说明:更完整的版本会先读取当前选中页的比例并预填到输入框,用户看到的是“当前选中页是1:2,是否全项目批量改成1:4”,而不是面对一个空白输入框。WinForms弹窗和EPLAN主窗口有一个常见冲突:对话框默认位置可能在任务栏而不是主窗口内,StartPosition要设为CenterParent,并且在ShowDialog()之前把EPLAN主窗口带到前端,否则用户以为插件没反应。

5. 避坑与常见问题:EPLAN API插件开发里最常踩的8个实测坑

5.1 菜单已经出现,但点击后没有任何反应:Action名不匹配

现象:插件加载成功,菜单项可见,点下去既不报错也没日志,OnAction根本没被调用。原因:大多数时候是AddMenuItem注册的Action名和OnAction里比较的字符串不一致,大小写不同也算。解决:把Action名定义成常量,注册、回调、日志都引用同一个常量;如果项目里插件多,统一加前缀,避免全局重名。这个坑几乎每个做EPLAN插件的人都遇到过,属于最没技术含量但最耗时间的一类问题。

5.2 属性赋值后,EPLAN项目里看到的还是旧值:少了Save或Refresh

现象:代码跑完没抛异常,回到EPLAN界面,页面比例、部件信息纹丝不动。原因:Properties赋值只是改内存里的属性集,没调用project.Save()持久化;或者保存了但界面还停留在旧缓存,看起来像没改。解决:批量处理结束统一调用Save()和Refresh()。注意不要在循环里逐页Save,一是慢,二是频繁写盘容易触发EPLAN的项目锁机制。如果想确认改动是否有效,可以在Save前主动读取一次属性值打日志。

5.3 插件被EPLAN静默忽略:平台位数和.NET Framework版本不匹配

现象:EPLAN正常启动,没任何错误提示,但菜单就是不出现。原因:插件工程平台位数是x86,而EPLAN是x64进程,CLR加载不了对应位数的程序集;另一种可能是目标框架选了.NET Core或.NET 5+,宿主识别不了。解决:工程目标框架确认是.NET Framework 4.x,平台配置选x64或AnyCPU(实际按x64运行),再清理重新编译。这类问题日志里往往没有明确错误,属于EPLAN插件开发里标准的黑匣子场景。

5.4 批量改完比例,封面页和表格页全乱了:过滤条件太粗

现象:用GetPages()遍历全项目改比例,改完发现封面页、表格页、宏页的比例和图框乱套。原因:GetPages()返回所有页类型,封面页和表格页的比例语义和原理图页不一样,对它们套用同一个比例值会破坏图框布局。解决:在循环里按PageType过滤,只处理你真正需要批量改的页类型;如果拿不准有哪些页类型,先写一个小工具把所有页类型和数量统计出来,再决定过滤条件。批量操作越是“无差别”,后续返工越痛苦。

5.5 F5调试时EPLAN崩溃或插件加载失败:残留进程抢占项目锁

现象:调试启动EPLAN时提示项目被占用,或上一次调试的EPLAN进程没退出,F5启动直接崩溃。原因:EPLAN对同一项目的打开有严格锁定,调试进程没释放,新进程再去打开同一个项目就会冲突。解决:调试前确认所有EPLAN进程已经关闭;更稳的做法是在Visual Studio的调试设置里把“启动外部程序”配好,并养成停调试就立即杀掉残留进程的习惯。不要在正式生产机上用杀进程脚本做预清理,风险太大。

5.6 代码改了,重新编译后EPLAN里还是旧逻辑:输出目录没刷新

现象:改了代码、重新编译、再启动EPLAN,行为还是旧版。原因:EPLAN加载的是公共文档目录下的插件DLL,而Visual Studio把新DLL输出到了项目bin目录,两个地方不一致。解决:在项目属性“生成事件”里加一个复制命令,把编译产物复制到EPLAN扫描目录,或者直接把输出路径改到EPLAN扫描目录。每次编译后检查一下目标目录里dll的时间戳,确认确实是新文件。

5.7 批量操作跑了一半报错:只读页和宏项目页写入被拒绝

现象:几百页的批量操作,跑到中间突然抛异常,整个插件中断,改了一部分没改完。原因:项目里存在只读子页、宏项目生成的页或者外部引用页,这些页不允许直接写属性。解决:在循环体里用try-catch捕获单页写入异常,把失败的页名累加到日志,跳过继续处理后续页;处理完统一输出一份“失败页清单”,让使用者知道哪些页需要人工处理。

5.8 插件的窗体显示在任务栏而不是EPLAN窗口里:焦点问题

现象:点击菜单后对话框出现在任务栏,EPLAN窗口没置前,用户以为没弹出来。原因:窗体的StartPosition和Owner设置不当,弹窗没有绑定到EPLAN主窗口。解决:创建窗体时传EPLAN主窗口引用作为Owner,设置StartPosition = CenterParent;如果版本差异导致拿不到主窗口句柄,可以在显示前调用激活方法把EPLAN主窗口带到前台。这种界面层的问题不影响数据逻辑,但最影响使用评价。

6. 从能跑到好用:EPLAN API插件的验证方法与几个进阶方向

插件能跑起来只是第一步,真正要交付给同事或客户,至少要过一遍验证流程。我会在自己的测试项目上做三件事:第一,改动前导出一份PDF或报表,改动后再导一份,用对比工具把两份差异拉出来,确认只有预期的属性在变;第二,批量操作后随机抽三到五页,逐页打开看属性面板里的实际值和日志是否一致;第三,把插件放到一个装好EPLAN但没装开发环境的机器上,验证部署目录、引用DLL和运行环境都正确。这三步能过滤掉绝大多数“在我机器上好好的”式交付问题。

进阶方向里最值得投入的是批量替换部件和自动生成报表。批量替换部件是在Function上操作关联的Part引用,注意保留厂商数据;自动生成报表则是用EPLAN自带的报表模板接口,把项目里的设备清单、端子排图批量输出成标准格式。这两个方向都是电气设计里加班最重的环节,做好了效率提升非常明显。如果和其他系统对接,例如把EPLAN项目里的BOM表同步到PLM或ERP,那就从插件内部调用外部Web API,注意处理好数据格式映射和大量数据的批量提交。

我现在的习惯是给每个插件单独建一个版本目录,编译产物带上时间戳,改动前先跑一遍第5章说的失败页清单功能。这些习惯一开始觉得啰嗦,但等插件被十个人用起来之后,你就知道日志和版本管理比功能本身还保命。EPLAN API这条路不难,难的是细节,希望这篇笔记帮你在细节上少折腾几回。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询