Skip to content
C#
API 概览与核心概念

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 的任何读取或写入都在事务的保护下。事务外的对象访问可能导致 AccessViolationExceptionObjectDisposedException


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())
{
    // 适合大量只读查询
}

StartOpenCloseTransactionStartTransaction 快 2-3 倍,且不产生撤销记录。适合遍历拓扑、导出数据等只读批量操作。