ARTICLE · 1102074
实战|用 AI 写 CAD 插件:一键删除标注(附源码 + 提示词)

点击蓝字,关注我们
这是《零基础 CAD 插件从 0 到 1》第 12 篇
做设计改图的朋友,清理标注绝对是个麻烦事情: 别人的图纸标注样式五花八门,没用的标注散得到处都是,一根根框选删除,删半天还容易带掉旁边的线条和文字; 想批量删掉某一种样式的标注,CAD 自带功能又没筛选,要么全删要么手动挑,眼睛瞅得发酸,删错了还得一步步撤销。 特别是改老图、改客户图的时候,光清理标注就能耗掉小半天才干正事。
今天咱们用 AI 写一个标注清理插件:支持框选批量删,也支持按标注样式一键全删,可视化窗口操作,只删标注不碰图形。清理图纸标注几秒搞定,不用手动挑、不怕删错,改图效率直接提上来。
先看效果:两种模式,标注清得干净又精准
先看两个核心场景的实际操作:

GIF1:打开一张满是杂乱标注的图纸 → 输入命令ALDELDIM→ 选择「框选删除」→ 框选杂乱标注 → 秒删干净,线条毫发无损。

GIF2:输入ALDELDIM→ 点击「拾取样式」→ 图纸里点一个标注 → 下拉框自动填入该样式 → 点「一键删除」→ 该样式标注瞬间清空 →Ctrl+Z撤销恢复。
不用一根根选,不用担心误删线条。 想删选中的就框选,想删某一类样式就直接选样式名,点一下就清干净,删错了 Ctrl+Z 还能撤销,安全又高效。
这个插件解决了什么问题?
针对标注清理效率低、容易误删的痛点,做了四个核心优化:
精准删除 只识别并删除选中的标注对象,自动过滤线条、文字、块、填充等其他图形,框选的时候不用小心翼翼,不会误删图纸内容。 按样式批量删除 下拉选择指定标注样式,自动查找全图所有该样式的标注并删除。清理外来图纸、统一标注规范的时候尤其好用,不用逐个筛选。 可视化界面 用标准窗口操作,直观明了,不用记命令参数,不用在命令行输选项,点选一下就能操作,新手也能上手。 支持撤销回退 所有删除操作都支持 CAD 原生撤销,删错了按 Ctrl+Z 就能恢复,不用担心手滑误操作。
交互设计:可视化窗口,两步搞定
完全贴合日常改图习惯,操作简单不用学:
- 启动命令
输入 ALDELDIM 回车,弹出操作窗口 - 选择删除方式
框选删除:点击按钮后回到图纸,可连续框选,按 ESC 结束命令
按样式删除:两种方式任选
下拉选择:直接从下拉框选样式名
拾取样式:点击按钮后去图纸里点一个标注,自动获取它的样式
没有复杂参数,没有多余步骤,打开就知道怎么用。
核心干货:给 AI 的精准提示词
还是那句话
用 AI 写插件写出来的功能不对,本质是需求没说细。AI 就像助理,你说清楚规则,它才能做准。下面是实测多轮、输出稳定能用的提示词模板,直接复制就能用:
角色设定:你是资深 CAD .NET 二次开发工程师,精通 C# 与 CAD 原生 API,面向全屋定制设计场景开发插件。 功能需求:开发一个「一键删除标注」的插件, 具体要求: 命令名:ALDELDIM 环境:.NET Framework 4.8,AutoCAD 2021,引用 AcMgd、AcDbMgd; 输出要求: 给出完整可复制编译的代码 关键逻辑加中文注释 说明编译和加载方法 |
写提示词的核心原则
先定身份先让 AI 进入专业 CAD 开发的角色,避免用错 API、写出行外代码。
再划边界明确命令名、CAD 版本、运行环境,从根源减少兼容问题和报错。
讲清规则怎么保存、怎么注入、怎么设为当前,每一步规则都说死,不给 AI 自由发挥的空间。
固定格式要完整代码、要注释、要部署说明,都明确提出来,输出直接能用。
照着这个结构写,AI 输出代码的可用率至少提升 80%。
核心源码分享
下面是核心实现代码,基于 C# + WPF + CAD .NET API 编写,两种删除模式,支持撤销操作。
using Autodesk.AutoCAD.ApplicationServices;using Autodesk.AutoCAD.Runtime;using AcApp = Autodesk.AutoCAD.ApplicationServices.Application;namespace DimDeletePlugin{public class Commands{[CommandMethod("ALDELDIM")]publicvoidAlDelDimCommand(){Document doc = AcApp.DocumentManager.MdiActiveDocument;if (doc == null) return;DimDeleteWindow win = new DimDeleteWindow();// 将 CAD 主窗口设为 WPF 窗口的 OwnerSystem.Windows.Interop.WindowInteropHelper helper =new System.Windows.Interop.WindowInteropHelper(win);helper.Owner = AcApp.MainWindow.Handle;// 使用 CAD 原生的模态窗口显示方法AcApp.ShowModalWindow(win);}}}
入口代码
using Autodesk.AutoCAD.ApplicationServices;using Autodesk.AutoCAD.DatabaseServices;using Autodesk.AutoCAD.EditorInput;using System;using System.Collections.Generic;using System.Windows;using System.Windows.Input;using AcApp = Autodesk.AutoCAD.ApplicationServices.Application;namespace DimDeletePlugin{public partial class DimDeleteWindow : Window{// 记住"拾取"到的样式的真实 ObjectId(手动选时为 Null)private ObjectId _pickedStyleId = ObjectId.Null;// 标志位:正在拾取过程中,防止 SelectionChanged 清空 _pickedStyleIdprivate bool _isPickingStyle = false;publicDimDeleteWindow(){InitializeComponent();LoadStyleList();}// ============================================================// 窗口交互// ============================================================privatevoidWindow_MouseDown(object sender, MouseButtonEventArgs e){if (e.LeftButton == MouseButtonState.Pressed)this.DragMove();}privatevoidBtnMinimize_Click(object sender, RoutedEventArgs e){this.WindowState = WindowState.Minimized;}privatevoidBtnClose_Click(object sender, RoutedEventArgs e){this.Close();}// ============================================================// 加载当前图纸所有"命名"标注样式到下拉框// ============================================================privatevoidLoadStyleList(){Document doc = AcApp.DocumentManager.MdiActiveDocument;if (doc == null) return;Database db = doc.Database;List<string> styleNames = new List<string>();using (Transaction tr = db.TransactionManager.StartTransaction()){DimStyleTable dst = tr.GetObject(db.DimStyleTableId, OpenMode.ForRead) as DimStyleTable;if (dst != null){foreach (ObjectId id in dst){DimStyleTableRecord dstr = tr.GetObject(id, OpenMode.ForRead) as DimStyleTableRecord;if (!dstr.Name.StartsWith("*"))styleNames.Add(dstr.Name);}}tr.Commit();}cmbStyle.ItemsSource = styleNames;if (styleNames.Count > 0)cmbStyle.SelectedIndex = 0;}// ============================================================// 下拉框选择变化:用户手动切换时清空拾取缓存// ============================================================privatevoidCmbStyle_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e){if (!_isPickingStyle)_pickedStyleId = ObjectId.Null;}// ============================================================// 模式一:框选删除// 可连续框选,按 ESC 结束命令// ============================================================privatevoidBtnSelectDelete_Click(object sender, RoutedEventArgs e){this.Hide();Document doc = AcApp.DocumentManager.MdiActiveDocument;if (doc == null) { this.Close(); return; }Editor ed = doc.Editor;Database db = doc.Database;int totalCount = 0;int roundCount = 0;SelectionFilter filter = new SelectionFilter(new TypedValue[]{new TypedValue((int)DxfCode.Start, "DIMENSION")});while (true){PromptSelectionOptions pso = new PromptSelectionOptions();if (roundCount == 0)pso.MessageForAdding = "\n请框选要删除的标注(按 ESC 结束命令) ";elsepso.MessageForAdding = $"\n请继续框选标注(已删除 {totalCount} 个,按 ESC 结束命令) ";pso.AllowDuplicates = false;PromptSelectionResult psr = ed.GetSelection(pso, filter);// ESC → 结束命令if (psr.Status == PromptStatus.Cancel){ed.WriteMessage($"\n命令结束,本次共删除 {totalCount} 个标注。");break;}// 空格/空回车 → 继续提示框选if (psr.Status == PromptStatus.None)continue;// 正常框选 → 删除后继续循环if (psr.Status == PromptStatus.OK && psr.Value.Count > 0){int count = 0;using (Transaction tr = db.TransactionManager.StartTransaction()){foreach (SelectedObject so in psr.Value){Entity ent = tr.GetObject(so.ObjectId, OpenMode.ForWrite) as Entity;if (ent != null){ent.Erase();count++;}}tr.Commit();}totalCount += count;roundCount++;ed.WriteMessage($"\n第 {roundCount} 次删除 {count} 个标注(累计 {totalCount} 个)");continue;}}this.Show();this.Activate();}// ============================================================// 拾取样式:从图纸中拾取一个标注,获取其样式// ============================================================privatevoidBtnPickStyle_Click(object sender, RoutedEventArgs e){Document doc = AcApp.DocumentManager.MdiActiveDocument;if (doc == null) return;Editor ed = doc.Editor;Database db = doc.Database;this.Hide();string styleName = null;ObjectId pickedId = ObjectId.Null;PromptEntityOptions peo = new PromptEntityOptions("\n请拾取一个标注对象以获取其样式 ");peo.SetRejectMessage("\n只能选择标注对象!");peo.AddAllowedClass(typeof(Dimension), false);PromptEntityResult per = ed.GetEntity(peo);if (per.Status == PromptStatus.OK){using (Transaction tr = db.TransactionManager.StartTransaction()){Dimension dim = tr.GetObject(per.ObjectId, OpenMode.ForRead) as Dimension;if (dim != null){pickedId = dim.DimensionStyle;DimStyleTableRecord dstr = tr.GetObject(pickedId, OpenMode.ForRead) as DimStyleTableRecord;if (dstr != null)styleName = dstr.Name;}tr.Commit();}}if (!string.IsNullOrEmpty(styleName) && !pickedId.IsNull){// 开启保护标志,防止 SelectionChanged 清空刚缓存的 Id_isPickingStyle = true;try{_pickedStyleId = pickedId;// 把样式名同步到下拉框var list = new List<string>();foreach (var item in cmbStyle.Items)list.Add(item.ToString());bool found = false;for (int i = 0; i < list.Count; i++){if (string.Equals(list[i].Trim(), styleName.Trim(), StringComparison.OrdinalIgnoreCase)){cmbStyle.SelectedIndex = i;found = true;break;}}if (!found){list.Add(styleName);cmbStyle.ItemsSource = null;cmbStyle.ItemsSource = list;cmbStyle.SelectedItem = styleName;}ed.WriteMessage($"\n已拾取样式:{styleName}");}finally{_isPickingStyle = false;}}this.Show();this.Activate();}// ============================================================// 模式二:按样式删除// 双保险匹配:样式名 + ObjectId,且必须在文档锁内执行// ============================================================privatevoidBtnStyleDelete_Click(object sender, RoutedEventArgs e){Document doc = AcApp.DocumentManager.MdiActiveDocument;if (doc == null) { this.Close(); return; }Database db = doc.Database;Editor ed = doc.Editor;if (cmbStyle.SelectedItem == null){MessageBox.Show("请先选择或拾取标注样式!", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);return;}string styleName = cmbStyle.SelectedItem.ToString();ObjectId pickedStyleId = _pickedStyleId;int count = 0;string errorInfo = null;this.Hide();try{// 关键:WPF 按钮事件修改图纸,必须手动锁文档using (DocumentLock docLock = doc.LockDocument()){// ========== 1. 拿当前空间所有标注 ==========TypedValue[] filterArr = new TypedValue[]{new TypedValue((int)DxfCode.Start, "DIMENSION")};SelectionFilter sf = new SelectionFilter(filterArr);PromptSelectionResult psr = ed.SelectAll(sf);if (psr.Status != PromptStatus.OK || psr.Value == null || psr.Value.Count == 0){MessageBox.Show("当前空间中没有任何标注。", "提示", MessageBoxButton.OK, MessageBoxImage.Information);this.Show();this.Activate();return;}// ========== 2. 单事务:边遍历边删除 ==========using (Transaction tr = db.TransactionManager.StartTransaction()){foreach (SelectedObject so in psr.Value){if (so == null || so.ObjectId.IsNull) continue;try{Dimension dim = tr.GetObject(so.ObjectId, OpenMode.ForRead) as Dimension;if (dim == null || dim.IsErased) continue;DimStyleTableRecord dstr = tr.GetObject(dim.DimensionStyle, OpenMode.ForRead) as DimStyleTableRecord;if (dstr == null) continue;// 双保险比较bool nameMatch = string.Equals(dstr.Name.Trim(),styleName.Trim(),StringComparison.OrdinalIgnoreCase);bool idMatch = (!pickedStyleId.IsNull) && (dim.DimensionStyle == pickedStyleId);if (nameMatch || idMatch){dim.UpgradeOpen();dim.Erase();count++;}}catch{continue;}}tr.Commit();}}_pickedStyleId = ObjectId.Null;ed.WriteMessage($"\n已删除样式「{styleName}」的标注共 {count} 个\n");}catch (System.Exception ex){errorInfo = $"{ex.GetType().Name}\n{ex.Message}";ed.WriteMessage($"\n删除过程出现异常:{ex.Message}");}if (errorInfo != null){MessageBox.Show($"删除过程出现异常:\n\n{errorInfo}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);}else{MessageBox.Show($"清理完成!共删除 {count} 个标注。\n如果删错了,可以按 Ctrl+Z 撤销。","执行成功", MessageBoxButton.OK, MessageBoxImage.Information);}this.Close();}}}
核心代码
说明:代码默认只删除模型空间的标注,可根据需要扩展布局空间;窗口样式、按钮文案都可以根据自己的使用习惯调整。
用 AI 开发插件的完整流程
这类工具型插件,用 AI 分步开发,上手最快:
- 需求拆解
把「一键删除标注」拆成「WPF 界面→选择集过滤删除→按样式遍历删除」三个模块,逐个让 AI 实现,不要一次性丢完整需求。 - 分步验证
先写选择集删除逻辑,测准只删标注不碰其他图形;再加样式删除逻辑,测准匹配和遍历;最后做 WPF 界面整合。每一步跑通再往下,出问题好定位。 - 实测优化
拿不同的图纸测试:比如带多种样式的图、带块里标注的图,看删除是否彻底、会不会误删;把遇到的问题丢给 AI,让它优化边界处理。 - 细节调整
比如窗口大小、按钮样式、是否加确认提示,都可以根据自己的操作习惯改,让 AI 直接调参数就行。
成品领取 & 下期预告
成品插件直接领
不想自己编译、调代码的朋友,关注公众号 「下班让AI教我做插件」,后台回复 「一键删除标注」,直接领取编译好的 DLL 插件文件,NETLOAD 加载或者是使用我写的dll插件加载工具箱。 完整工程源码拿到手就能二次修改。
下期预告
下一篇咱们继续深化标注提效工具,如果有想要的插件可以在评论区留言,我看看哪个留言最多就做哪个。
我是做插件的设计师,专注用 AI 提高 CAD 设计效率。关注我,下班一起做插件,把重复工作交给程序。

E
N
D