API 概览与核心概念
本章讲解 AutoCAD .NET API 的核心架构:Application、Document、Database、Editor 和 Transaction。理解这些是写出稳定插件的前提。
核心对象层次
Application (应用程序,全局单例)
└── DocumentManager
└── Document (每个打开的 DWG 对应一个 Document)
├── Database (图形数据库,存储所有对象)
├── Editor (命令行交互、用户输入)
└── TransactionManager
└── Transaction (操作 Database 的单元)Application
using Autodesk.AutoCAD.ApplicationServices;
// 获取活动文档
Document doc = Application.DocumentManager.MdiActiveDocument;
// 获取所有打开的文档
DocumentCollection docs = Application.DocumentManager;
// 新建文档
Document newDoc = Application.DocumentManager.Add("Template.dwt");
// 打开文档
Document openedDoc = Application.DocumentManager.Open(filePath, false);
// 文档切换事件
Application.DocumentManager.DocumentActivated += (s, e) =>
{
Console.WriteLine($"切换到:{e.Document.Name}");
};
// 应用程序级别
string version = Application.Version; // "24.3s (LMS Tech)"
ProductKey key = Application.ProductKey; // "R24.3"Document 与 Database
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
// Database 是图形数据库,包含所有符号表和命名对象字典
// 常用符号表:
// BlockTable — 块定义(包含模型空间和图纸空间)
// LayerTable — 图层
// LinetypeTable — 线型
// TextStyleTable — 文字样式
// DimStyleTable — 标注样式
// RegAppTable — 注册应用程序名
// UcsTable — 用户坐标系获取符号表
using (Transaction tr = db.TransactionManager.StartTransaction())
{
// 获取块表
BlockTable bt = (BlockTable)tr.GetObject(
db.BlockTableId, OpenMode.ForRead);
// 获取模型空间
BlockTableRecord modelSpace = (BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
// 获取图层表
LayerTable lt = (LayerTable)tr.GetObject(
db.LayerTableId, OpenMode.ForRead);
tr.Commit();
}Editor
Editor ed = doc.Editor;
// 输出消息(不换行用 \n 开始)
ed.WriteMessage("\n处理完成,共 {0} 个实体", count);
// 获取用户输入(详见 05-用户交互)
PromptPointResult ppr = ed.GetPoint("\n请选择一个点:");
if (ppr.Status == PromptStatus.OK)
{
Point3d pt = ppr.Value;
}
// 刷新显示
ed.Regen();Transaction(事务)—— 最核心的概念
几乎所有 Database 操作都必须在 Transaction 中执行:
Database db = Application.DocumentManager.MdiActiveDocument.Database;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
// 打开对象:
// OpenMode.ForRead — 只读
// OpenMode.ForWrite — 可修改
Line line = tr.GetObject(lineId, OpenMode.ForRead) as Line;
// 添加对象到数据库
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
BlockTableRecord modelSpace = (BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
Circle circle = new Circle(center, Vector3d.ZAxis, radius);
modelSpace.AppendEntity(circle);
tr.AddNewlyCreatedDBObject(circle, true); // 纳入事务管理
tr.Commit(); // 必须提交!
}🚨 没有 Transaction = 无法操作数据库。对 Database 的任何读取或写入都在事务的保护下。事务外的对象访问可能导致
AccessViolationException或ObjectDisposedException。
ObjectId—— 实体句柄
AutoCAD 中,图形对象不直接持有引用,而是通过 ObjectId 索引:
// ObjectId 常用属性
ObjectId id = line.ObjectId;
bool isValid = id.IsValid; // 是否指向有效对象
bool isErased = id.IsErased; // 是否已删除
IntPtr handle = id.Handle.Value; // 64 位句柄
// 通过 Handle 获取 ObjectId
Handle h = new Handle(12345);
ObjectId id = db.GetObjectId(false, h, 0);
// 遍历模型空间获取所有实体 ID
using (Transaction tr = db.TransactionManager.StartTransaction())
{
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
BlockTableRecord modelSpace = (BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace], OpenMode.ForRead);
foreach (ObjectId id in modelSpace)
{
Entity entity = tr.GetObject(id, OpenMode.ForRead) as Entity;
if (entity != null)
{
ed.WriteMessage($"\n{entity.GetType().Name} Layer={entity.Layer}");
}
}
tr.Commit();
}💡
ObjectId本身是轻量的值类型,无需事务即可持有。但通过ObjectId获取实际对象(GetObject)必须在事务中。
读取 vs 写入模式
| OpenMode | 用途 | 说明 |
|---|---|---|
ForRead |
只读访问 | 默认选择,不标记对象为已修改 |
ForWrite |
修改/创建 | 标记为脏,撤销文件增大 |
ForNotify |
通知读写 | 特殊场景 |
ForWrite (upgrade) |
先 ForRead 后升级为 ForWrite | obj.UpgradeOpen() |
// 大部分场景只需 ForRead
Circle circle = tr.GetObject(id, OpenMode.ForRead) as Circle;
double radius = circle.Radius; // 读取属性:ForRead 即可
Point3d center = circle.Center;
// 修改时必须 ForWrite
Circle circle = tr.GetObject(id, OpenMode.ForWrite) as Circle;
circle.Radius = 100.0; // 修改:必须 ForWrite
// 升级打开(避免长时间持有写锁)
Circle circle = tr.GetObject(id, OpenMode.ForRead) as Circle;
if (circle.Radius < 10)
{
circle.UpgradeOpen(); // 升级为写
circle.Radius = 10;
circle.DowngradeOpen(); // 降级回读
}🔬
ForWrite持有比ForRead更重的锁。在 CAD 多文档环境中,尽量减少写锁持有时间。
完整工作流:创建一条直线
[CommandMethod("DRAWLINE")]
public void DrawLineCommand()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
using (Transaction tr = db.TransactionManager.StartTransaction())
{
// 1. 获取模型空间
BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
BlockTableRecord modelSpace = (BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace], OpenMode.ForWrite);
// 2. 创建实体
Line line = new Line(
new Point3d(0, 0, 0),
new Point3d(100, 100, 0)
);
line.Layer = "0";
line.ColorIndex = 1; // 红色
// 3. 添加到模型空间
modelSpace.AppendEntity(line);
tr.AddNewlyCreatedDBObject(line, true);
tr.Commit();
}
doc.Editor.WriteMessage("\n直线已创建。");
}StartOpenCloseTransaction(性能优化)
AutoCAD 2015+ 提供轻量级事务:
// 传统事务(完整功能,有撤销记录)
using (Transaction tr = db.TransactionManager.StartTransaction())
{
// 适合修改操作
}
// 开放关闭事务(更轻量,无撤销开销)
using (Transaction tr = db.TransactionManager.StartOpenCloseTransaction())
{
// 适合大量只读查询
}⚡
StartOpenCloseTransaction比StartTransaction快 2-3 倍,且不产生撤销记录。适合遍历拓扑、导出数据等只读批量操作。