本帖最后由 wang2006zhi 于 2025-11-5 14:40 编辑
封装参数为:AssociationManager.AssocObjects(textId1, () =>{});
封装参数为:AssociationManager.AssocObjects(sId,tId, () =>{});
测试2
网友答: 关于AssocAction,CAD有自带的,ifox群有我的代码示例网友答:
网友答:
网友答:
发个图片看看呀网友答:
本帖最后由 wang2006zhi 于 2025-11-5 13:16 编辑
复制代码网友答:
经过提醒,在IFOX群里找到了相关示例。。。基于此,本文不再设置付费主题观看网友答: 本帖最后由 你有种再说一遍 于 2025-11-4 15:59 编辑
标注关联有没有做过?我发现官方在标注关联是有bug的,例如跨空间标注关联,然后我们要附着岂不是有相同bug?网友答:
没有,目前没这方面的业务需求
网友答:
作者怎么被封啦???也没有看他刷帖啊

- <div class="blockcode"><blockquote>/// <summary>
- /// 简化版链式关联管理器
- /// </summary>
- public static class AssociationManager
- {
- #region 内部结构
-
- /// <summary>
- /// 关联信息
- /// </summary>
- private class AssociationAction
- {
- public Action? Action { get; set; }
- public string Tag { get; set; } = "";
- }
- // 关联存储:源对象ID -> 关联信息列表
- private static readonly Dictionary<ObjectId, List<AssociationAction>> Associations = new();
-
- // 防止递归更新的标记集合
- private static readonly HashSet<ObjectId> UpdatingObjects = new();
-
- // 初始化标志
- private static bool _isInitialized;
- #endregion
- #region 公共API
- /// <summary>
- /// 创建对象关联
- /// </summary>
- /// <param name="sourceId">源对象ID</param>
- /// <param name="action">无参数关联动作</param>
- /// <param name="tag">关联标签</param>
- public static void AssocObjects(ObjectId sourceId, Action? action, string tag = "")
- {
- EnsureInitialized();
-
- if (sourceId.IsNull || action == null)
- return;
- // 获取或创建关联列表
- if (!Associations.ContainsKey(sourceId))
- Associations[sourceId] = new List<AssociationAction>();
- // 检查是否已存在相同标签的关联
- var existing = Associations[sourceId].FirstOrDefault(a => a.Tag == tag);
- if (existing != null)
- existing.Action = action; // 更新现有关联
- else // 添加新关联
- Associations[sourceId].Add(new AssociationAction
- {
- Action = action,
- Tag = tag
- });
- }
- /// <summary>
- /// 移除对象的所有关联
- /// </summary>
- public static void RemoveAssociations(ObjectId sourceId)
- {
- Associations.Remove(sourceId);
- }
- /// <summary>
- /// 移除特定标签的关联
- /// </summary>
- public static void RemoveAssociation(ObjectId sourceId, string tag)
- {
- if (!Associations.TryGetValue(sourceId, out var association)) return;
-
- association.RemoveAll(a => a.Tag == tag);
- if (Associations[sourceId].Count == 0)
- Associations.Remove(sourceId);
- }
- /// <summary>
- /// 手动触发关联更新
- /// </summary>
- /// <param name="sourceId">源对象ID</param>
- public static void UpdateAssociations(ObjectId sourceId)
- {
- if (!Associations.ContainsKey(sourceId) || UpdatingObjects.Contains(sourceId))
- return;
- ExecuteAssociations(sourceId);
- }
- /// <summary>
- /// 检查是否存在关联
- /// </summary>
- public static bool HasAssociations(ObjectId sourceId)
- {
- return Associations.ContainsKey(sourceId);
- }
- /// <summary>
- /// 获取关联统计信息
- /// </summary>
- public static string GetStats()
- {
- var sourceCount = Associations.Count;
- var totalAssociations = Associations.Values.Sum(list => list.Count);
- return $"关联源对象: {sourceCount}, 总关联数: {totalAssociations}";
- }
- #endregion
- #region 核心实现
- /// <summary>
- /// 确保管理器已初始化
- /// </summary>
- private static void EnsureInitialized()
- {
- if (_isInitialized) return;
-
- var doc = Acaop.DocumentManager.MdiActiveDocument;
- if (doc == null) return;
- // 移除旧的事件处理(防止重复注册)
- doc.Database.ObjectModified -= OnObjectModified;
- doc.Database.ObjectErased -= OnObjectErased;
-
- // 注册新的事件处理
- doc.Database.ObjectModified += OnObjectModified;
- doc.Database.ObjectErased += OnObjectErased;
- _isInitialized = true;
- }
- /// <summary>
- /// 执行关联动作
- /// </summary>
- private static void ExecuteAssociations(ObjectId sourceId)
- {
- if (!Associations.ContainsKey(sourceId) || UpdatingObjects.Contains(sourceId))
- return;
- try
- {
- UpdatingObjects.Add(sourceId);
-
- foreach (var actionInfo in Associations[sourceId].ToList())
- {
- try
- {
- // 执行关联动作
- actionInfo.Action?.Invoke();
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"关联执行失败 [{actionInfo.Tag}]: {ex.Message}");
- }
- }
- }
- finally
- {
- UpdatingObjects.Remove(sourceId);
- }
- }
- /// <summary>
- /// 对象修改事件处理
- /// </summary>
- private static void OnObjectModified(object sender, ObjectEventArgs e)
- {
- if (!Associations.ContainsKey(e.DBObject.Id) ||
- UpdatingObjects.Contains(e.DBObject.Id))
- return;
- ExecuteAssociations(e.DBObject.Id);
- }
- /// <summary>
- /// 对象删除事件处理
- /// </summary>
- private static void OnObjectErased(object sender, ObjectErasedEventArgs e)
- {
- // 移除被删除对象的关联
- RemoveAssociations(e.DBObject.Id);
- }
- #endregion
- }

- namespace HTJ.Arx;
- /// <summary>
- /// 简化版链式关联管理器 - 使用无参数Action,支持1->2->3链式关联,防止闭环
- /// </summary>
- public static class AssociationManager
- {
- #region 内部结构
- /// <summary>
- /// 关联信息
- /// </summary>
- private class AssociationAction
- {
- public ObjectId TargetId { get; set; }
- public Action? Action { get; set; }
- public string Tag { get; set; } = "";
- }
- // 关联存储:源对象ID -> 关联信息列表
- private static readonly Dictionary<ObjectId, List<AssociationAction>> Associations = new();
- // 防止递归更新的标记集合
- private static readonly HashSet<ObjectId> UpdatingObjects = new();
- // 初始化标志
- private static bool _isInitialized;
- #endregion
- #region 公共API
- /// <summary>
- /// 创建对象关联
- /// </summary>
- /// <param name="sourceId">源对象ID</param>
- /// <param name="targetId">目标对象ID</param>
- /// <param name="action">无参数关联动作</param>
- /// <param name="tag">关联标签</param>
- /// <exception cref="InvalidOperationException">检测到闭环关联时抛出</exception>
- public static void AssocObjects(ObjectId sourceId, ObjectId targetId,
- Action? action, string tag = "")
- {
- EnsureInitialized();
- if (sourceId.IsNull || targetId.IsNull || action == null)
- return;
- // 检查是否会造成闭环
- if (WouldCreateCycle(sourceId, targetId)) throw new InvalidOperationException("创建此关联会导致闭环,这是不允许的");
- // 获取或创建关联列表
- if (!Associations.ContainsKey(sourceId)) Associations[sourceId] = new List<AssociationAction>();
- // 检查是否已存在相同标签的关联
- var existing = Associations[sourceId].FirstOrDefault(a => a.Tag == tag);
- if (existing != null)
- existing.Action = action; // 更新现有关联
- else
- // 添加新关联
- Associations[sourceId].Add(new AssociationAction
- {
- TargetId = targetId,
- Action = action,
- Tag = tag
- });
- }
- /// <summary>
- /// 移除对象的所有关联
- /// </summary>
- private static void RemoveAssociations(ObjectId sourceId)
- {
- Associations.Remove(sourceId);
- }
- /// <summary>
- /// 移除特定标签的关联
- /// </summary>
- public static void RemoveAssociation(ObjectId sourceId, string tag)
- {
- if (!Associations.TryGetValue(sourceId, out var association)) return;
- association.RemoveAll(a => a.Tag == tag);
- if (Associations[sourceId].Count == 0) Associations.Remove(sourceId);
- }
- /// <summary>
- /// 手动触发关联更新
- /// </summary>
- /// <param name="sourceId">源对象ID</param>
- public static void UpdateAssociations(ObjectId sourceId)
- {
- if (!Associations.ContainsKey(sourceId) || UpdatingObjects.Contains(sourceId))
- return;
- ExecuteAssociations(sourceId);
- }
- /// <summary>
- /// 检查是否存在关联
- /// </summary>
- public static bool HasAssociations(ObjectId sourceId)
- {
- return Associations.ContainsKey(sourceId);
- }
- /// <summary>
- /// 获取关联统计信息
- /// </summary>
- public static string GetStats()
- {
- var sourceCount = Associations.Count;
- var totalAssociations = Associations.Values.Sum(list => list.Count);
- return $"关联源对象: {sourceCount}, 总关联数: {totalAssociations}";
- }
- #endregion
- #region 核心实现
- /// <summary>
- /// 确保管理器已初始化
- /// </summary>
- private static void EnsureInitialized()
- {
- if (_isInitialized) return;
- var doc = Acaop.DocumentManager.MdiActiveDocument;
- if (doc != null)
- {
- doc.Database.ObjectModified += OnObjectModified;
- doc.Database.ObjectErased += OnObjectErased;
- _isInitialized = true;
- }
- }
- /// <summary>
- /// 检查是否会造成闭环
- /// </summary>
- private static bool WouldCreateCycle(ObjectId sourceId, ObjectId targetId)
- {
- // 如果目标对象已经是源对象的祖先,则形成闭环
- return IsAncestor(targetId, sourceId, new HashSet<ObjectId>());
- }
- /// <summary>
- /// 检查targetId是否是sourceId的祖先
- /// </summary>
- private static bool IsAncestor(ObjectId sourceId, ObjectId targetId, HashSet<ObjectId> visited)
- {
- if (sourceId == targetId)
- return true;
- if (!visited.Add(sourceId))
- return false;
- if (!Associations.TryGetValue(sourceId, out var association)) return false;
- foreach (var action in association)
- if (IsAncestor(action.TargetId, targetId, visited))
- return true;
- return false;
- }
- /// <summary>
- /// 执行关联动作
- /// </summary>
- private static void ExecuteAssociations(ObjectId sourceId)
- {
- if (!Associations.ContainsKey(sourceId) || UpdatingObjects.Contains(sourceId))
- return;
- try
- {
- UpdatingObjects.Add(sourceId);
- foreach (var actionInfo in Associations[sourceId].ToList())
- try
- {
- // 执行关联动作
- actionInfo.Action?.Invoke();
- // 递归执行链式关联
- if (Associations.ContainsKey(actionInfo.TargetId))
- ExecuteAssociations(actionInfo.TargetId);
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"关联执行失败 [{actionInfo.Tag}]: {ex.Message}");
- }
- }
- finally
- {
- UpdatingObjects.Remove(sourceId);
- }
- }
- /// <summary>
- /// 对象修改事件处理
- /// </summary>
- private static void OnObjectModified(object sender, ObjectEventArgs e)
- {
- if (!Associations.ContainsKey(e.DBObject.Id) ||
- UpdatingObjects.Contains(e.DBObject.Id))
- return;
- ExecuteAssociations(e.DBObject.Id);
- }
- /// <summary>
- /// 对象删除事件处理
- /// </summary>
- private static void OnObjectErased(object sender, ObjectErasedEventArgs e)
- {
- // 移除被删除对象的关联
- RemoveAssociations(e.DBObject.Id);
- // 移除指向被删除对象的所有关联
- foreach (var sourceId in Associations.Keys.ToList())
- {
- Associations[sourceId].RemoveAll(action => action.TargetId == e.DBObject.Id);
- if (Associations[sourceId].Count == 0) Associations.Remove(sourceId);
- }
- }
- #endregion
- }

- [CommandMethod("tt8")]
- public void Tt8()
- {
- if (!Env.Editor.SelId(out ObjectId textId1,RxClassEx.DbText))
- return;
- if (!Env.Editor.SelId(out ObjectId circleId,RxClassEx.Circle))
- return;
- if (!Env.Editor.SelId(out ObjectId textId2,RxClassEx.DbText))
- return;
- // 创建图形属性关联
- AssociationManager.AssocObjects(textId1,circleId,() =>
- {
- using var tr = new DBTrans(docLock: false);
- if (tr.GetObject(textId1) is not DBText text1)
- return;
- if (tr.GetObject(circleId,OpenMode.ForWrite) is not Circle circle)
- return;
- circle.Radius=text1.TextString.ToDouble();
- circle.ColorIndex=1;
- if (tr.GetObject(textId2,OpenMode.ForWrite) is not DBText text2)
- return;
- text2.TextString = $"半径: {circle.Radius:F2}";
- },"1->2");
- // 创建关联:文字显示圆的半径和面积
- AssociationManager.AssocObjects(circleId,textId2,() =>
- {
- using var tr = new DBTrans(docLock: false);
- if (tr.GetObject(circleId) is not Circle circle)
- return;
- if (tr.GetObject(textId2,OpenMode.ForWrite) is not DBText text2)
- return;
- text2.TextString = $"半径: {circle.Radius:F2}";
- },"2->3");
网友答: 关于AssocAction,CAD有自带的,ifox群有我的代码示例网友答:

- namespace HTJ.Arx;
- /// <summary>
- /// 关联动作体封装
- /// BY2025.11;wang2006zhi
- /// </summary>
- /// <remarks>
- /// 使用示例:
- /// <code>
- /// var logic = new Dictionary{
- /// [textId] = trans => { /* 文字更新逻辑 */ },
- /// [circleId] = trans => { /* 圆更新逻辑 */ }
- /// };
- /// AssocActionEx.Create(logic);
- /// </code>
- /// </remarks>
- public class AssocActionEx : AssocActionBody
- {
- #region 私有字段
- private ObjectId _assocActionId = ObjectId.Null;
- private readonly List<ObjectId> _sourceObjectIds = [];
- private readonly Dictionary<ObjectId, Action<AssocObjectTransaction>> _objectUpdateActions = [];
- private readonly List<Action<AssocObjectTransaction>> _globalUpdateActions = [];
- private Func<AssocActionEx>? _cloneFactory;
- private bool _cloneFlag;
- #endregion
- #region 公共接口
- /// <summary>
- /// 创建关联动作
- /// </summary>
- /// <param name="objectSpecificLogic">
- /// 对象特定逻辑字典,Key为对象ID(自动作为依赖对象),Value为对应的更新逻辑
- /// </param>
- /// <param name="cloneFactory">深克隆时的创建工厂,用于对象复制时创建新的关联动作实例</param>
- /// <returns>创建的关联动作实例</returns>
- /// <exception cref="ArgumentNullException">当逻辑字典为空时抛出</exception>
- /// <exception cref="ArgumentException">当逻辑字典为空时抛出</exception>
- public static AssocActionEx Create(Dictionary<ObjectId, Action<AssocObjectTransaction>> objectSpecificLogic,
- Func<AssocActionEx>? cloneFactory = null)
- {
- if (objectSpecificLogic == null) throw new ArgumentNullException(nameof(objectSpecificLogic));
- if (objectSpecificLogic.Count == 0) throw new ArgumentException(@"对象特定逻辑字典不能为空", nameof(objectSpecificLogic));
- var action = new AssocActionEx();
- if (cloneFactory != null) action._cloneFactory = cloneFactory;
- // 直接从字典的键获取依赖对象,并设置更新逻辑
- action.SetupDependenciesAndLogic(objectSpecificLogic);
- return action;
- }
- /// <summary>
- /// 添加全局更新逻辑(对所有依赖对象生效)
- /// </summary>
- /// <param name="logic">全局更新逻辑,会在每次评估时执行</param>
- /// <returns>当前实例以支持链式调用</returns>
- /// <exception cref="ArgumentNullException">当逻辑为空时抛出</exception>
- public AssocActionEx AddGlobalLogic(Action<AssocObjectTransaction> logic)
- {
- _globalUpdateActions.Add(logic ?? throw new ArgumentNullException(nameof(logic)));
- return this;
- }
- /// <summary>
- /// 设置深克隆工厂函数
- /// </summary>
- /// <param name="factory">创建新实例的工厂函数,在对象被复制时调用</param>
- /// <returns>当前实例以支持链式调用</returns>
- /// <exception cref="ArgumentNullException">当工厂函数为空时抛出</exception>
- public AssocActionEx SetCloneFactory(Func<AssocActionEx> factory)
- {
- _cloneFactory = factory ?? throw new ArgumentNullException(nameof(factory));
- return this;
- }
- #endregion
- #region 内部实现
- /// <summary>
- /// 设置依赖关系并创建关联动作
- /// </summary>
- /// <param name="objectSpecificLogic">对象特定逻辑字典</param>
- private void SetupDependenciesAndLogic(Dictionary<ObjectId, Action<AssocObjectTransaction>> objectSpecificLogic)
- {
- var ids = objectSpecificLogic.Keys.ToList();
- // 设置依赖关系
- SetupDependencies(ids);
- // 设置对象特定逻辑
- foreach (var kv in objectSpecificLogic) _objectUpdateActions[kv.Key] = kv.Value;
- }
- /// <summary>
- /// 获取需要处理的对象列表
- /// </summary>
- /// <param name="transaction">关联事务</param>
- /// <returns>需要更新的对象ID列表</returns>
- private List<ObjectId> GetPendingObjects(AssocObjectTransaction transaction)
- {
- var objectIdCollection = GetDependencies(true, true);
- var pendingObjectIds = new List<ObjectId>(objectIdCollection.Count);
- // 遍历所有依赖项,检查哪些需要更新
- foreach (ObjectId dependencyId in objectIdCollection)
- {
- using var dependency =
- (AssocDependency)transaction.GetDBObject(dependencyId, OpenMode.ForRead, false, true);
- // 如果依赖项状态不是"已更新",则添加到待处理列表
- if (dependency.Status != AssocStatus.IsUpToDateAssocStatus)
- {
- pendingObjectIds.Add(dependency.DependentOnObject);
- }
- }
- return pendingObjectIds;
- }
- /// <summary>
- /// 获取或创建关联动作对象
- /// </summary>
- /// <param name="owningObjectId">所属对象ID</param>
- /// <param name="tr">数据库事务</param>
- /// <returns>关联动作对象</returns>
- private AssocAction GetOrCreateAssocAction(ObjectId owningObjectId, DBTrans tr)
- {
- // 如果已经存在关联动作,直接返回
- if (!_assocActionId.IsNull) return tr.GetObject<AssocAction>(_assocActionId, OpenMode.ForWrite)!;
- var database = tr.Database;
- // 获取或创建关联网络
- var networkObjectId = AssocNetwork.GetInstanceFromObject(owningObjectId, true, true, "");
- var network = tr.GetObject<AssocNetwork>(networkObjectId, OpenMode.ForWrite)!;
- // 创建关联动作
- var assocAction = new AssocAction();
- var actionBodyObjectId = database.AddDBObject(this);
- // 注册新创建的对象到事务中
- tr.Transaction.AddNewlyCreatedDBObject(this, true);
- _assocActionId = database.AddDBObject(assocAction);
- assocAction.ActionBody = actionBodyObjectId;
- network.AddAction(_assocActionId, true);
- return assocAction;
- }
- /// <summary>
- /// 评估逻辑 - 执行所有注册的更新动作
- /// </summary>
- /// <remarks>
- /// 这是关联动作的核心方法,当依赖对象发生变化时自动调用
- /// </remarks>
- public override void EvaluateOverride()
- {
- try
- {
- var assocEvaluationCallback = currentEvaluationCallback();
- // 检查评估模式是否为"修改对象"模式
- if (assocEvaluationCallback.EvaluationMode() != AssocEvaluationMode.ModifyObjectsAssocEvaluationMode)
- {
- Status = AssocStatus.FailedToEvaluateAssocStatus;
- return;
- }
- // 检查是否存在被删除或损坏的依赖项
- if (HasAnyErasedOrBrokenDependencies())
- {
- Status = AssocStatus.ErasedAssocStatus;
- return;
- }
- using var transaction = new AssocObjectTransaction(this);
- // 获取需要更新的对象
- var pendingObjects = GetPendingObjects(transaction);
- if (pendingObjects.Count == 0)
- {
- Status = AssocStatus.IsUpToDateAssocStatus;
- return;
- }
- // 评估依赖项状态
- EvaluateDependencies();
- // 执行对象特定的更新逻辑
- ExecuteObjectSpecificLogic(pendingObjects, transaction);
- // 执行全局更新逻辑
- ExecuteGlobalLogic(transaction);
- // 标记状态为已更新
- Status = AssocStatus.IsUpToDateAssocStatus;
- }
- catch (Exception ex)
- {
- // 记录异常并标记为评估失败
- $"关联动作评估失败: {ex.Message}".Print();
- Status = AssocStatus.FailedToEvaluateAssocStatus;
- }
- }
- /// <summary>
- /// 执行对象特定的更新逻辑
- /// </summary>
- /// <param name="pendingObjects">待处理对象列表</param>
- /// <param name="transaction">关联事务</param>
- private void ExecuteObjectSpecificLogic(List<ObjectId> pendingObjects, AssocObjectTransaction transaction)
- {
- foreach (var objectId in pendingObjects)
- {
- if (!_objectUpdateActions.TryGetValue(objectId, out var objectLogic)) continue;
- try
- {
- objectLogic(transaction);
- }
- catch (Exception ex)
- {
- $"对象特定逻辑执行失败 {objectId}: {ex.Message}".Print();;
- }
- }
- }
- /// <summary>
- /// 执行全局更新逻辑
- /// </summary>
- /// <param name="transaction">关联事务</param>
- private void ExecuteGlobalLogic(AssocObjectTransaction transaction)
- {
- foreach (var globalLogic in _globalUpdateActions)
- {
- try
- {
- globalLogic(transaction);
- }
- catch (Exception ex)
- {
- $"全局逻辑执行失败: {ex.Message}".Print();
- }
- }
- }
- /// <summary>
- /// 深克隆处理 - 当关联对象被复制时调用
- /// </summary>
- /// <param name="idMap">对象ID映射关系</param>
- /// <param name="additionalObjectsToClone">额外需要克隆的对象集合</param>
- /// <remarks>
- /// 此方法确保当依赖对象被复制时,关联动作也会被正确复制
- /// </remarks>
- public override void AddMoreObjectsToDeepCloneOverride(IdMapping idMap, ObjectIdCollection additionalObjectsToClone)
- {
- if (_cloneFlag) return;
- _cloneFlag = true;
- try
- {
- using var tr = new DBTrans();
- // 收集已克隆的对象ID
- var (clonedIds, originalIds) = CollectClonedIds(idMap);
- // 克隆缺失的依赖对象
- CloneMissingDependencies(clonedIds, originalIds, tr);
- // 创建新的关联动作实例并复制逻辑
- CreateClonedActionBody(clonedIds, idMap);
- }
- finally
- {
- _cloneFlag = false;
- }
- }
- /// <summary>
- /// 收集已克隆的对象ID
- /// </summary>
- /// <param name="idMap">ID映射表</param>
- /// <returns>克隆后的ID列表和原始ID列表</returns>
- private (List<ObjectId> clonedIds, List<ObjectId> originalIds) CollectClonedIds(IdMapping idMap)
- {
- var length = idMap.GetValues().Count;
- var clonedIds = new List<ObjectId>(length);
- var originalIds = new List<ObjectId>(length);
- foreach (IdPair idPair in idMap)
- {
- clonedIds.Add(idPair.Value);
- originalIds.Add(idPair.Key);
- }
- return (clonedIds, originalIds);
- }
- /// <summary>
- /// 克隆缺失的依赖对象
- /// </summary>
- /// <param name="clonedIds">已克隆的ID列表</param>
- /// <param name="originalIds">原始ID列表</param>
- /// <param name="tr">数据库事务</param>
- private void CloneMissingDependencies(List<ObjectId> clonedIds, List<ObjectId> originalIds, DBTrans tr)
- {
- // 检查是否有缺失的依赖对象需要克隆
- if (clonedIds.Count >= _sourceObjectIds.Count) return;
- var missingIds = _sourceObjectIds.Except(originalIds).ToArray();
- if (missingIds.Length == 0) return;
- // 执行深克隆操作
- var objectIdCollection = new ObjectIdCollection(missingIds);
- using var idMapping = new IdMapping();
- tr.Database.DeepCloneObjects(objectIdCollection, tr.CurrentSpace.ObjectId, idMapping, false);
- // 添加新克隆的对象ID到列表中
- foreach (IdPair idPair in idMapping)
- {
- clonedIds.Add(idPair.Value);
- }
- }
- private void CreateClonedActionBody(List<ObjectId> clonedIds, IdMapping idMap)
- {
- // 创建新的动作体实例
- var newBody = _cloneFactory?.Invoke() ?? new AssocActionEx();
- // 设置依赖关系(使用克隆后的ID列表)
- newBody.SetupDependencies(clonedIds);
- // 复制对象特定逻辑(映射到克隆后的对象ID)
- foreach (var kv in _objectUpdateActions)
- {
- var originalId = kv.Key;
- var logic = kv.Value;
- var clonedId = FindClonedId(originalId, idMap);
- if (clonedId.IsValid) newBody._objectUpdateActions[clonedId] = logic;
- }
- // 复制全局逻辑
- newBody._globalUpdateActions.AddRange(_globalUpdateActions);
- }
- /// <summary>
- /// 设置依赖关系
- /// </summary>
- /// <param name="ids">依赖对象ID列表</param>
- private void SetupDependencies(IList<ObjectId> ids)
- {
- if (ids.Count == 0) return;
- using var tr = new DBTrans();
- var first = ids[0];
- var database = first.Database;
- // 验证数据库状态
- if (database == null)
- {
- "数据库不可用".Print();
- return;
- }
- // 获取或创建关联动作
- var assocAction = GetOrCreateAssocAction(first, tr);
- // 在事务中创建依赖关系
- using var transaction = database.TransactionManager.StartTransaction();
- for (int i = 0; i < ids.Count; i++)
- {
- var entityId = ids;
- if (!IsObjectSuitableForAssociation(entityId, tr))
- {
- $"对象 {entityId} 不适合作为关联依赖,已跳过".Print();
- continue;
- }
- _sourceObjectIds.Add(entityId);
- // 创建依赖项
- var dependency = new AssocDependency();
- var dependencyId = database.AddDBObject(dependency);
- // 配置依赖项属性
- dependency.AttachToObject(new CompoundObjectId(entityId));
- dependency.IsReadDependency = true;
- dependency.IsWriteDependency = true;
- dependency.Order = i;
- // 将依赖项添加到关联动作
- assocAction.AddDependency(dependencyId, true);
- }
- transaction.Commit();
- }
- /// <summary>
- /// 检查对象是否适合作为关联依赖
- /// </summary>
- private bool IsObjectSuitableForAssociation(ObjectId objectId, DBTrans tr)
- {
- try
- {
- if (objectId.IsNull || !objectId.IsValid)
- return false;
- using var obj = tr.Transaction.GetObject(objectId, OpenMode.ForRead, false, true);
- // 检查对象类型
- if (obj is BlockReference || obj is BlockTableRecord)
- {
- "块引用和块表记录不适合作为关联依赖".Print();
- return false;
- }
- // 检查对象是否已被擦除
- if (obj.IsErased)
- {
- "对象已被擦除".Print();
- return false;
- }
- return true;
- }
- catch
- {
- return false;
- }
- }
- /// <summary>
- /// 查找克隆后的对象ID
- /// </summary>
- /// <param name="originalId">原始对象ID</param>
- /// <param name="idMap">ID映射表</param>
- /// <returns>克隆后的对象ID,如果找不到则返回ObjectId.Null</returns>
- private static ObjectId FindClonedId(ObjectId originalId, IdMapping idMap)
- {
- foreach (IdPair idPair in idMap)
- {
- if (idPair.Key == originalId) return idPair.Value;
- }
- return ObjectId.Null;
- }
- #endregion
- }
- if (!IsObjectSuitableForAssociation(entityId, tr))

- namespace HTJ.Arx;
- /// <summary>
- /// 封装的动作体基类
- /// BY 徐蕾来自IFOX
- /// </summary>
- public abstract class AssocActionEx : AssocActionBody
- {
- /// <summary>
- /// 所在的动作的objectid
- /// </summary>
- private ObjectId AssocActionId { get; set; } = ObjectId.Null;
- /// <summary>
- /// 外部传入的对象id缓存
- /// </summary>
- private readonly List<ObjectId> _sourceObjectIds = [];
-
- /// <summary>
- /// 添加依赖到动作中
- /// </summary>
- /// <param name="tr"></param>
- /// <param name="isRead"></param>
- /// <param name="isWrite"></param>
- /// <param name="ids"></param>
- public virtual void AddDependency(IList<ObjectId> ids, DBTrans tr, bool isRead = true, bool isWrite = true)
- {
- if (!ids.Any()) return;
- var first = ids.First();
- var database = first.Database;
- // 假设 GetAssocAction 已经通过事务获取对象
- AssocAction assocAction = GetAssocAction(first, tr);
- // 确保在事务内部执行所有操作
- using Transaction transaction = database.TransactionManager.StartTransaction();
- for (int i = 0; i < ids.Count; i++)
- {
- var entity = ids[i];
- _sourceObjectIds.Add(entity);
-
- var dependency = new AssocDependency();
- var dependecyId = database.AddDBObject(dependency);
-
- dependency.AttachToObject(new CompoundObjectId(entity));
- dependency.IsReadDependency = isRead;
- dependency.IsWriteDependency = isWrite;
- dependency.Order = i;
-
- assocAction.AddDependency(dependecyId, true);
- }
- transaction.Commit();
- }
- /// <summary>
- /// 生成子类实例的抽象方法,用于实体复制事件中的占位
- /// </summary>
- /// <returns></returns>
- protected abstract AssocActionEx CreateAssocActionBody();
-
- /// <summary>
- /// 具体的更新实体逻辑
- /// </summary>
- /// <param name="objectId"></param>
- /// <param name="aTransaction"></param>
- protected abstract void UpdateEntity(ObjectId objectId, AssocObjectTransaction aTransaction);
-
- /// <summary>
- /// 获取动作
- /// </summary>
- /// <param name="owningObjectId">要查找关联网络的对象的 OwnerId(通常是块表记录或字典的 ID)</param>
- /// <param name="tr"></param>
- /// <returns></returns>
- /// <exception cref="InvalidOperationException"></exception>
- private AssocAction GetAssocAction(ObjectId owningObjectId, DBTrans tr)
- {
- if (!AssocActionId.IsNull) return tr.GetObject<AssocAction>(AssocActionId, OpenMode.ForWrite)!;
- var database = tr.Database;
- //获取或创建关联网络的objectid
- //第一个false表示没有就创建新的
- //第二个true表示加入顶级网路(不明所以)
- var networkObjectid = AssocNetwork.GetInstanceFromObject(owningObjectId, true, true, "");
- // 以写入模式获取网络对象
- var network = tr.GetObject<AssocNetwork>(networkObjectid, OpenMode.ForWrite)!;
- // 创建关联动作对象
- var assocAction = new AssocAction();
- // 将动作体添加到数据库
- var actionBodyObjectid = database.AddDBObject(this);
- // 在事务中注册新创建的动作体
- tr.Transaction.AddNewlyCreatedDBObject(this, true);
- // 将动作添加到数据库
- AssocActionId = database.AddDBObject(assocAction);
- // 关联动作对象设置其动作体
- assocAction.ActionBody = actionBodyObjectid;
- // 将动作添加到网络中
- network.AddAction(AssocActionId, true);
- return assocAction;
- }
- /// <summary>
- /// 获取实体上包含的动作
- /// </summary>
- /// <param name="entity"></param>
- /// <param name="tr"></param>
- /// <returns></returns>
- /// <exception cref="InvalidOperationException"></exception>
- private AssocAction GetAssocAction(Entity entity, DBTrans tr)
- {
- return !entity.ObjectId.IsOk() ? throw new InvalidOperationException() : GetAssocAction(entity.OwnerId, tr);
- }
-
- /// <summary>
- /// 重写 AssocActionBody 的 EvaluateOverride 方法,用于自定义关联动作的评估逻辑
- /// </summary>
- public override void EvaluateOverride()
- {
- // 获取当前关联评估的回调接口
- var assocEvaluationCallback = currentEvaluationCallback();
- // 检查评估模式是否为"修改对象"模式,如果不是则标记为失败并退出
- if (assocEvaluationCallback.EvaluationMode() != AssocEvaluationMode.ModifyObjectsAssocEvaluationMode)
- {
- Status = AssocStatus.FailedToEvaluateAssocStatus;
- return;
- }
- // 检查是否存在被删除或损坏的依赖项,如果是则标记为"已删除"状态并退出
- if (HasAnyErasedOrBrokenDependencies())
- {
- Status = AssocStatus.ErasedAssocStatus;
- return;
- }
- // 创建一个关联对象事务(自动释放资源)
- using var transaction = new AssocObjectTransaction(this);
- // 获取所有依赖项(包括直接和间接依赖)
- var objectIdCollection = GetDependencies(true, true);
- //标记是否需要更新
- bool isUpToDateAssocStatus = true;
- //待处理的实体id集合
- List<ObjectId> pendingObjectids = [];
- foreach (ObjectId objectId in objectIdCollection)
- {
- // 以只读方式打开依赖项(AssocDependency 对象)
- using AssocDependency dependency = (AssocDependency)transaction.GetDBObject(objectId, OpenMode.ForRead, false, true);
- if (dependency.Status is AssocStatus.IsUpToDateAssocStatus) continue;
- isUpToDateAssocStatus = false;
- pendingObjectids.Add(dependency.DependentOnObject);
- }
- // 显式评估所有依赖项的状态
- EvaluateDependencies();
- // 如果依赖项都已是最新状态,则直接标记为最新并退出
- if (isUpToDateAssocStatus)
- {
- Status = AssocStatus.IsUpToDateAssocStatus;
- return;
- }
- //各个子类实现相应的动作
- //UpdateEntity(pendingObjectids, transaction);
- foreach (ObjectId objectId in pendingObjectids)
- {
- UpdateEntity(objectId, transaction);
- }
- // 标记当前状态为"已更新"
- Status = AssocStatus.IsUpToDateAssocStatus;
- }
- private bool _cloneFlag;
- public override void AddMoreObjectsToDeepCloneOverride(IdMapping idMap, ObjectIdCollection additionalObjectsToClone)
- {
- if (_cloneFlag) return;
- using var tr = new DBTrans();
- List<ObjectId> ids = [];
- List<ObjectId> objectids = [];
- foreach (IdPair idPair in idMap)
- {
- ids.Add(idPair.Value);
- objectids.Add(idPair.Key);
- }
- if (ids.Count < _sourceObjectIds.Count)
- {
- var except = _sourceObjectIds.Except(objectids).ToArray();
- var objectIdCollection = new ObjectIdCollection(except);
- using IdMapping idMapping = [];
- _cloneFlag = true;
- //深度克隆
- tr.Database.DeepCloneObjects(objectIdCollection, tr.CurrentSpace.ObjectId, idMapping, false);
- _cloneFlag = false;
- foreach (IdPair idPair in idMapping)
- {
- ids.Add(idPair.Value);
- }
- }
- // 创建自定义动作体实例
- var body = this.CreateAssocActionBody();
- //添加依赖
- body.AddDependency(ids, tr);
- }
-
- }记录一下
- 演示
d1742647821 发表于 2025-11-4 11:44
关于AssocAction,CAD有自带的,ifox群有我的代码示例
经过提醒,在IFOX群里找到了相关示例。。。基于此,本文不再设置付费主题观看网友答: 本帖最后由 你有种再说一遍 于 2025-11-4 15:59 编辑
标注关联有没有做过?我发现官方在标注关联是有bug的,例如跨空间标注关联,然后我们要附着岂不是有相同bug?网友答:
你有种再说一遍 发表于 2025-11-4 15:49
标注关联有没有做过?我发现官方在标注关联是有bug的,例如跨空间标注关联,然后我们要附着岂不是有相同bug?
没有,目前没这方面的业务需求
网友答:
作者怎么被封啦???也没有看他刷帖啊