事件监听 ——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变色功能");

}

}

}

相关推荐
唐青枫4 小时前
C#.NET dapper 详解
c#·.net
死也不注释7 小时前
【鸡零狗碎记录】
unity·c#
Maybe_ch7 小时前
.NET-键控服务依赖注入
开发语言·c#·.net
★YUI★10 小时前
学习游戏制作记录(剑投掷技能)7.26
学习·游戏·unity·c#
小乖兽技术11 小时前
C#与C++交互开发系列(二十四):WinForms 应用中嵌入C++ 原生窗体
c++·c#·交互
I'mSQL12 小时前
C#与WPF使用mvvm简单案例点击按钮触发弹窗
开发语言·c#·wpf
工藤新一OL12 小时前
把xml的格式从utf-8-bom转为utf-8
xml·c#·asp.net·.netcore·visual studio
henreash13 小时前
NLua和C#交互
开发语言·c#·交互
SAJalon17 小时前
C#集合全面解析
c#
SAJalon19 小时前
C#数组全面解析
c#