简介:一套面向Tekla二次开发入门者的C#源代码示例包,聚焦图纸管理自动化场景,帮助钢结构详图设计人员理解如何通过应用程序接口载入模型图纸列表、实现图纸选择与打开操作,并从中提取尺寸、位置、角度、材料等关键数值。压缩包共二十个文件,以六个C#源代码文件为核心,辅以工程文件、解决方案、资源文件以及设置配置文件,构成完整的Visual Studio项目结构,可直接编译运行;另有Visual Studio状态文件用于保留开发环境设置。整个包体仅七十四KB,轻量精炼,适合初学者快速下载研读。已有七百八十五人学习下载。源码中包含启动模型查看器、设置视角与隐藏线显示等视图控制逻辑,以及处理用户选择事件的界面代码,覆盖了从数据查询到界面交互的完整链路,读者可借此掌握Tekla图纸模块二次开发的基本流程与接口调用方式,并延伸出更多定制化功能,提升详图设计效率。
1. Tekla二次开发图纸入门:这份源代码包,三个立得住的起点
第一次拿到 Tekla 二次开发的图纸源码,很多人第一反应是“代码在哪”。图纸不是模型,它有一套独立的 DrawingHandler 对象树,视图、标注、过滤规则都藏在图纸被激活之后才能访问的上下文里。这份 Tekla二次开发图纸入门源码包,把从环境配置到图纸遍历、尺寸操作的完整路径都走了一遍,适合刚接手图纸自动化的工程师,也适合想快速验证 API 用法的熟手。先别急着写业务逻辑,把绘图环境立起来,后面所有代码才能跑得动。图纸模块的 API 并不难,难的是入口没找对,后面全是玄学。
2. 环境和入口:SDK 版本选型与连接图纸模块的代码骨架
2.1 开发环境:SDK 版本与 .NET 框架怎么选
Tekla 图纸二次开发的前提是装好和当前 Tekla 版本对应的 SDK。Windows 下查看 Tekla Structures 安装目录,通常能找到 SDK 的 sample 工程。以 Tekla Structures 2024 左右的版本为例,SDK 提供的主要 DLL 分布在安装目录下的 nT\bin 或 Common\bin 里,最常见的四个引用是 Tekla.Structures.dll、Tekla.Structures.Drawing.dll、Tekla.Structures.Model.dll 和 Tekla.Structures.Catalogs.dll。
项目创建时,常见做法是选 .NET Framework 4.7.2 或 4.8,而不是 .NET Core。原因是 Tekla Open API 原生绑定 .NET Framework,部分版本对高版本 .NET 的支持不完整。引用 DLL 时建议把“复制本地”设为 false,否则会把几十兆的 SDK 文件拷到输出目录,后续版本升级容易造成文件冲突。
还有一点容易被忽略:SDK 版本要和当前安装的 Tekla 主版本一致。某开发者在项目里用 2023 的 SDK 连 2024 的模型,编译正常,但运行时提示类型加载失败,换成配套版本后问题消失。如果同时装了多个 Tekla 版本,引用 DLL 前先在“引用管理器”里确认文件路径属于当前激活版本。
2.2 连接模型与图纸命令的最小代码骨架
图纸操作前必须先连接模型。Tekla 的模型连接是全局单例,代码写在 Main 里即可。下面是一个最小可用骨架。
using Tekla.Structures.Model; using Tekla.Structures.Drawing; using TSM = Tekla.Structures.Model; namespace TeklaDrawingQuickStart { class Program { static void Main(string[] args) { // 第一步:连接当前打开的 Tekla 模型 TSM.Model model = new TSM.Model(); if (!model.GetConnectionStatus()) { System.Console.WriteLine("未连接到模型,请先在有模型打开的 Tekla 环境中运行"); return; } System.Console.WriteLine("模型连接成功:" + model.GetModelName()); // 第二步:进入图纸模块 DrawingHandler drawingHandler = new DrawingHandler(); if (!drawingHandler.GetConnectionStatus()) { System.Console.WriteLine("图纸工具未就绪,可能需要先打开一张图纸"); return; } System.Console.WriteLine("图纸模块连接成功"); } } }逻辑说明:第一处 GetConnectionStatus() 判断模型是否在线,第二处判断图纸模块是否可用。很多新手只判断模型,不判断 DrawingHandler,后续调用返回空对象时才一脸茫然。
参数说明:model.GetModelName() 返回当前模型名称,用于日志输出确认连接的是不是预期模型。DrawingHandler 是进入图纸模块的唯一入口,所有图纸对象的遍历都从它开始。调试时最好在 Tekla 里开着一个空模型,再按下 F5 附加到 Tekla 进程。
运行方式有两种:一种是以外部插件方式附加进程调试,另一种是编译成 .tsep 安装包在 Tekla 内部运行。日常验证代码建议用前者,省去打包流程,改代码立刻生效。
3. 图纸对象模型:从 Handler 到视图的三层结构与坐标问题
3.1 图纸对象树:DrawingHandler 到 Drawing 到 View
图纸模块的对象模型比模型模块更隐蔽。模型里可以直接拿 ModelObjectEnumerator 扫全部构件,图纸里必须先拿到 Drawing 集合,再逐张进到 Sheet,最后到 View,一层层往下走。
using Tekla.Structures.Drawing; using Tekla.Structures; public void ListAllViews() { DrawingHandler handler = new DrawingHandler(); if (!handler.GetConnectionStatus()) return; // 拿到当前模型里的所有图纸 DrawingCollection drawings = handler.GetDrawings(); foreach (Drawing drawing in drawings) { System.Console.WriteLine("图纸:" + drawing.Name); // 每张图纸对应一个 Sheet,图纸页 Sheet sheet = drawing.GetSheet(); if (sheet == null) { System.Console.WriteLine(" 该图纸没有可用的 Sheet,跳过"); continue; } // Sheet 下面才是视图集合 ViewCollection views = sheet.GetViews(); foreach (View view in views) { System.Console.WriteLine(" 视图:" + view.Name + " 原点:" + view.Origin); } } }逻辑说明:GetDrawings() 返回当前模型关联的全部图纸集合,注意这里拿到的是引用,不是拷贝。GetSheet() 拿到当前图纸的图页,图纸模板的 Sheet 通常为空。GetViews() 返回该图页下的所有视图,视图里才真正包含零件对象。
参数说明:view.Name 是视图在图纸里的名称,view.Origin 是视图原点在图纸坐标系下的位置,调试定位视图时这个信息比坐标转换靠谱得多。打印出来的 Origin 还能辅助判断视图是否被移到图纸边界外。
一个容易误会的地方:DrawingCollection 不是 List,它没有 Count 属性,只能 foreach 遍历。如果确实需要知道图纸数量,用变量自己累加。想按名字找图纸,就在循环里比对 drawing.Name,不要指望 API 给索引器。
3.2 图纸坐标与模型坐标:为什么标注会跑到图纸外
图纸里的坐标体系与模型坐标完全不同。模型坐标是三维世界坐标,图纸坐标是二维平面坐标。试图把模型坐标直接塞给图纸对象的 InsertPoint,常见结果是元素跑到图纸外,或者偏移一个固定量。
正确姿势是先拿到视图的坐标系或变换信息。视图对象上通常有相关的属性用于描述视图在图纸中的位置关系,常见做法是先取视图原点,再计算目标点在视图中的相对位置,最后转换成图纸坐标。
using Tekla.Structures.Drawing; using Tekla.Structures.Geometry3d; public Point ConvertToSheetPoint(View view, Point modelPoint) { // 取视图原点作为基准 Point viewOrigin = view.Origin as Point; if (viewOrigin == null) return null; // 视图内的点:以视图原点为参考做偏移 double dx = modelPoint.X - viewOrigin.X; double dy = modelPoint.Y - viewOrigin.Y; // 换算到图纸平面坐标,Z 在图纸里通常为 0 return new Point(dx, dy, 0.0); }逻辑说明:这段代码做了简化处理,适合视图没有旋转、图纸方向与模型平面基本一致的常见场景。真实项目中视图可能带旋转角,处理方法是读取视图的平面变换矩阵,再把模型点乘进去,而不是手动减原点。
参数说明:dx 和 dy 是目标点相对视图原点的偏移量。注意模型点的单位是毫米,Tekla 内部默认单位为毫米,不需要额外换算。返回的 Point 直接作为图纸对象的放置点使用。
这个坐标坑是图纸二次开发里最典型的“黑匣子”问题:代码逻辑看着对,运行结果却偏得离谱。调试时建议先打印视图原点和目标点的坐标值,手工算一遍偏移,再决定要不要处理旋转。
4. 把代码写到图纸上:视图遍历、零件标记和尺寸操作怎么落地
4.1 实现按名称过滤的视图定位
实际项目中图纸数量很多,直接在 DrawingCollection 里全量遍历,批处理时容易被无关图纸拖慢。常见做法是先按图纸名前缀过滤,再按视图名定位。
using Tekla.Structures.Drawing; public View FindViewByKeyword(DrawingHandler handler, string drawingKeyword, string viewKeyword) { DrawingCollection drawings = handler.GetDrawings(); foreach (Drawing drawing in drawings) { if (!drawing.Name.Contains(drawingKeyword)) continue; Sheet sheet = drawing.GetSheet(); if (sheet == null) continue; ViewCollection views = sheet.GetViews(); foreach (View view in views) { if (view.Name.Contains(viewKeyword)) { return view; } } } return null; }逻辑说明:先过滤图纸名,再过滤视图名。Contains 是模糊匹配,适合名称带编号的图纸。如果图纸命名规则固定,可以用 StartsWith 提高匹配精度。
参数说明:drawingKeyword 建议传图纸类型前缀,比如“GA”或“WQ”,viewKeyword 传视图类型名,比如“立面”或“剖面”。返回值 View 可以直接用于后续插入标注,找不到时返回 null,调用方要做好判空。
这个方法看似简单,却是整个图纸自动化流程的地基。批处理时只要把 drawingKeyword 和 viewKeyword 对上,后面的操作就全部可控。
4.2 添加零件标记与标注的常用流程
图纸自动化里最高频的操作是给零件加标记。Tekla 图纸 API 里没有全局的“添加标记”方法,常见做法是拿到目标视图后,遍历视图内对象,再调用视图对象的相关插入接口。下面是一个流程级别的示意代码。
using Tekla.Structures.Drawing; using Tekla.Structures.Model; public int AddMarksToView(View targetView, string markContent) { if (targetView == null) return 0; // 获取视图内的对象集合 DrawingObjectCollection objects = targetView.GetObjects(); if (objects == null) return 0; int count = 0; foreach (DrawingObject drawingObject in objects) { // 只处理零件对象,过滤掉尺寸、文本等 if (!(drawingObject is Part part)) continue; // 构造标记放置点:取零件在视图中的位置 Point insertionPoint = part.GetInsertionPoint() as Point; if (insertionPoint == null) continue; // 创建标记对象 Mark mark = new Mark(targetView, part); mark.MarkContent = markContent; mark.InsertionPoint = insertionPoint; // 插入到视图 if (mark.Insert()) { count++; } } return count; }逻辑说明:GetObjects() 返回视图内的所有图纸对象,包括零件、尺寸、文本、符号等。用 is Part 过滤后,剩下的就是图纸零件。Mark 对象需要同时指定所属视图和关联零件,这是因为 Tekla 图纸中的标记必须绑定到一个真实对象上,不能脱离零件独立存在。
参数说明:markContent 是标记内容模板,常见写法是包含属性占位符。insertionPoint 是标记的插入位置,工程中通常还要配合一个偏移量,避免标记覆盖零件本身。Insert() 返回 bool,可以用来统计成功插入数量,失败时打印日志定位问题。
尺寸操作与标记类似,先取视图对象集合,过滤出需要标注的构件边或交点,再创建 Dimension 对象。尺寸标注更复杂的地方在于需要指定标注方向的坐标轴,处理不当时容易出现尺寸线交叉。新手建议先从零件标记练手,跑通后再做尺寸。
4.3 批处理时如何控制图纸打开关闭的节奏
Tekla 图纸对象在后台是可以批量操作的,不用在界面上逐张打开。但要注意:大量创建标记之后,内存中的图纸对象会持续累积。常见做法是每处理完一张图纸就释放一次对象引用。
public void BatchProcessAllViews() { DrawingHandler handler = new DrawingHandler(); if (!handler.GetConnectionStatus()) return; DrawingCollection drawings = handler.GetDrawings(); foreach (Drawing drawing in drawings) { Sheet sheet = drawing.GetSheet(); if (sheet == null) continue; ViewCollection views = sheet.GetViews(); foreach (View view in views) { AddMarksToView(view, "PART_MARK"); } // 主动清空该图纸的引用,避免集合对象堆积 System.GC.Collect(); } }逻辑说明:GC.Collect() 是强制的垃圾回收,在批处理场景里可以有效压住内存峰值,但每次调用会带来性能开销。更优雅的做法是去掉几行局部变量作用域,让对象在循环体结束后自然释放。
参数说明:PART_MARK 是标记内容的模拟占位,实际项目里通常配置成 Tekla 标记模板的变量名。批处理跑完后,建议用 DrawingHandler 的保存方法统一提交修改,而不是依赖 Tekla 自动保存。
5. 高频翻车点排查:图纸模块的四个常见异常与解决顺序
5.1 现象:模型明明开着,DrawingHandler 却连不上
模型连接成功,但 new DrawingHandler() 之后 GetConnectionStatus() 返回 false。
原因:DrawingHandler 连接的不只是模型,还需要 Tekla 图纸环境处于激活状态。某些情况下 Tekla 启动后模型已打开,但图纸后台服务还没初始化完成,特别是 Tekla 刚打开大模型时,图纸模块加载需要时间。
解决:不要立刻重试,引入等待机制。常见做法是循环调用 GetConnectionStatus(),每次间隔 500 毫秒,最多等 10 秒。另一个偏方是先手动打开一张图纸再运行脚本,图纸环境被激活后连接基本稳定。
5.2 现象:view.GetObjects() 返回的零件比模型少很多
明明模型里有 200 根构件,视图里遍历出来只有 80 个。
原因:图纸视图本身有过滤条件。Tekla 视图对象上有图纸过滤规则,视图只显示满足条件的零件。另一个原因是遍历的视图不是主视图,辅助视图或详图视图的可见范围天然受限。
解决:先检查视图的过滤属性,把过滤条件设为“显示全部”再遍历。其次确认目标视图是主视图还是辅助视图。打印视图名称和坐标,对比 UI 里的图纸,很快能定位是哪个视图。
5.3 现象:获取的插入点偏移,标注飞到图纸外
代码逻辑按坐标换算写了,但插入标记的位置明显不对。
原因:最常见的原因是视图带有旋转角,简单减法忽略了视图自身的变换矩阵。其次是部分对象返回的插入点是模型坐标,没有先转换到图纸坐标。
解决:先打印目标零件在模型中的坐标和视图原点,手工确认偏差量。确认存在旋转后,改用视图的平面变换接口做坐标映射。可以写一个专用的坐标转换工具方法,所有插入点统一走这个方法,避免散落在业务代码里的零散换算。
5.4 现象:批处理跑几分钟后内存暴涨甚至卡死
图纸数量一多,脚本运行越来越慢,最后 Tekla 无响应。
原因:循环内持续创建 DrawingObject 集合,且集合对象没有被及时释放。Tekla 的图纸对象是非托管资源,单纯依赖 .NET 垃圾回收不能及时释放。
解决:每处理完一张图纸调用一次 GC.Collect(),同时把不再使用的局部变量显式置为 null。更彻底的做法是把批处理拆成多个小任务,每处理 10 张图纸暂停一次,等 Tekla 恢复响应再继续。经验值是单次批处理图纸数量超过 50 张时,强制分段执行比一次跑完更稳定。
6. 进阶:把常用图纸操作封装成一个批处理小工具类
到这一步,你已经能跑通图纸遍历和标记插入。真正让这些代码可复用的是把它们封装成一个工具类,输入图纸关键词、视图关键词、标记内容,输出成功标记数量。下面是一个可直接扩展的工具形状。
using Tekla.Structures.Drawing; public class DrawingBatchTool { private DrawingHandler _handler; public DrawingBatchTool() { _handler = new DrawingHandler(); if (!_handler.GetConnectionStatus()) { throw new System.Exception("图纸模块连接失败"); } } public void Run(string drawingKeyword, string viewKeyword, string markContent) { int totalMarkCount = 0; DrawingCollection drawings = _handler.GetDrawings(); foreach (Drawing drawing in drawings) { if (!drawing.Name.Contains(drawingKeyword)) continue; Sheet sheet = drawing.GetSheet(); if (sheet == null) continue; ViewCollection views = sheet.GetViews(); foreach (View view in views) { if (!view.Name.Contains(viewKeyword)) continue; totalMarkCount += AddMarksToView(view, markContent); } System.Console.WriteLine($"图纸 {drawing.Name} 处理完成"); System.GC.Collect(); } System.Console.WriteLine($"全部完成,共添加 {totalMarkCount} 个标记"); } private int AddMarksToView(View view, string markContent) { // 中间的遍历与插入逻辑,同上一节 return 0; } }逻辑说明:所有操作通过 Run 方法入口串联,参数集中暴露。工具类里把 AddMarksToView 设为私有方法,避免外部误用。这样批处理命令就能变成一行调用,也方便后续接自动化工作流。
验证方法:跑完脚本后,在 Tekla 界面里随机打开三张图纸,检查标记位置是否在零件轮廓附近、标记内容是否完整。批量日志里的成功数量只能证明插入接口返回成功,不能证明位置正确,最终要以人眼抽查为准。
从那以后我每次写图纸脚本,都会先跑一遍空模型验证连接状态,再做单个图纸测试,最后才放批处理。这个顺序看起来笨,但真能挡住大部分翻车现场。希望帮到你。
本文还有配套的精品资源,点击获取