事件监听 ——CAD C#二次开发

一、AutoCAD .NET API 事件机制

  1. 事件监听核心
  • Database.ModifyObjects 事件

当数据库中的实体(如图形对象)发生修改时触发,包括:

  • 几何属性变更(移动、缩放、旋转)。

  • 非几何属性变更(颜色、线型、图层)。

  • 删除或复制操作(需结合事件参数判断)。

  • 事件参数 ObjectModifiedEventArgs

  • GetModifiedObjectIds(OpenMode) :获取修改的实体ID列表, OpenMode 控制访问权限(如 ForRead 或 ForWrite )。

  • 通过遍历实体ID,获取对应的 Entity 对象进行操作。

二、实体移动检测原理

  1. 几何包围盒( GeometricExtents )
  • 定义:

每个实体( Entity )都有一个 GeometricExtents 属性,表示其在三维空间中的最小包围盒,包含:

  • MinPoint :包围盒最小角点坐标(X,Y,Z)。

  • MaxPoint :包围盒最大角点坐标(X,Y,Z)。

  • 中心点计算:

中心点 = (MinPoint + MaxPoint) / 2 ,用于表征实体的位置。

移动判断逻辑:若修改前后中心点坐标差异超过阈值(如 1e-9 ),则认为实体发生移动

核心逻辑流程

  1. 事件注册:

通过 RegisterIndexEvent 命令绑定 ModifyObjects 事件,开始监听实体修改。

  1. 移动检测:
  • 遍历所有修改的实体,获取新旧版本的包围盒中心点。

  • 对比中心点差异,判断是否为移动操作。

  1. 颜色变更:
  • 生成随机 ColorIndex ,排除绿色(3号)和当前颜色索引。

  • 直接设置 entity.ColorIndex = newIndex ,触发视觉更新。

  1. 事件注销:

通过 UnregisterIndexEvent 移除事件监听,释放资源。

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Geometry;

using System;

public class ColorIndexChangeDemo

{

private Document doc;

private Database db;

private Editor ed;

private const int GreenColorIndex = 3; // 绿色对应的ColorIndex(3号色为标准绿色)

private readonly Random random = new Random();

CommandMethod("RegisterIndexEvent")

public void RegisterIndexEvent()

{

doc = Application.DocumentManager.MdiActiveDocument;

db = doc.Database;

ed = doc.Editor;

db.ModifyObjects += OnEntityMoved; // 注册移动事件

ed.WriteMessage("\n已启用ColorIndex变色功能(避免3号绿色)");

}

private void OnEntityMoved(object sender, ObjectModifiedEventArgs e)

{

try

{

using (Transaction trans = doc.TransactionManager.StartTransaction())

{

foreach (ObjectId objId in e.GetModifiedObjectIds(OpenMode.ForWrite))

{

Entity entity = trans.GetObject(objId, OpenMode.ForWrite) as Entity;

if (entity == null) continue;

// 检测移动(基于包围盒中心点)

if (IsEntityMoved(entity, trans))

{

ChangeColorByIndex(entity); // 修改ColorIndex

ed.WriteMessage($"\n实体{entity.GetType().Name}颜色已更新为索引{entity.ColorIndex}");

}

}

trans.Commit();

}

}

catch (Exception ex)

{

ed.WriteMessage($"\n错误:{ex.Message}");

}

}

/// <summary>

/// 检测实体移动(包围盒中心点变化)

/// </summary>

private bool IsEntityMoved(Entity entity, Transaction trans)

{

using (DBObject oldObj = trans.GetObject(entity.Id, OpenMode.ForRead, true))

{

if (oldObj is not Entity oldEntity) return false;

return !GetCenter(oldEntity).IsEqualTo(GetCenter(entity), 1e-9);

}

}

/// <summary>

/// 获取包围盒中心点

/// </summary>

private Point3d GetCenter(Entity entity)

{

GeometricExtents extents = entity.GeometricExtents;

return extents.IsValid ?

new Point3d((extents.MinPoint.X + extents.MaxPoint.X)/2,

(extents.MinPoint.Y + extents.MaxPoint.Y)/2,

(extents.MinPoint.Z + extents.MaxPoint.Z)/2) :

Point3d.Origin;

}

/// <summary>

/// 安全修改ColorIndex(避开绿色和当前索引)

/// </summary>

private void ChangeColorByIndex(Entity entity)

{

int currentIndex = entity.ColorIndex; // 获取当前索引

int newIndex;

do

{

// 生成1-255的随机索引(ColorIndex范围:0=随层,1-255为具体颜色)

newIndex = random.Next(1, 256);

} while (newIndex == GreenColorIndex || newIndex == currentIndex); // 排除绿色和当前索引

entity.ColorIndex = newIndex; // 直接设置索引

}

CommandMethod("UnregisterIndexEvent")

public void UnregisterIndexEvent()

{

if (db != null)

{

db.ModifyObjects -= OnEntityMoved;

ed.WriteMessage("\n已停止ColorIndex变色功能");

}

}

}

相关推荐
张人玉18 小时前
C# TCP 客户端开发笔记(TcpClient)
笔记·tcp/ip·c#
张人玉21 小时前
C# 通讯关键类的API
开发语言·c#
William_cl1 天前
C# MVC 修复DataTable时间排序以及中英文系统的时间筛选问题
开发语言·c#·mvc
c#上位机1 天前
wpf之RelativeSource用法总结
c#·wpf
Dm_dotnet1 天前
WPF应用最小化到系统托盘
c#
*长铗归来*1 天前
ASP.NET Core Web API 中控制器操作的返回类型及Swagger
后端·c#·asp.net·.netcore
R-G-B1 天前
【06】C#入门到精通——C# 多个 .cs文件项目 同一项目下添加多个 .cs文件
开发语言·c#·c# 多个 .cs文件项目
懒人Ethan2 天前
解决一个C# 在Framework 4.5反序列化的问题
java·前端·c#
mysolisoft2 天前
Avalonia+ReactiveUI实现记录自动更新
c#·avalonia·reactiveui·sourcegenerator
心疼你的一切2 天前
使用Unity引擎开发Rokid主机应用的模型交互操作
游戏·ui·unity·c#·游戏引擎·交互