Bao_lai 发表于 2025-11-6 12:04:38

tranque 发表于 2025-11-6 09:49
最后登录时间 1970-1-1 ennnnnnnnnnnnnnn

看看我的也是哦(_)

tranque 发表于 2025-11-6 12:43:12

Bao_lai 发表于 2025-11-6 12:04
看看我的也是哦(_)

有点酷,怎么做到的

wang2006zhi 发表于 2025-11-12 09:04:48

你有种再说一遍 发表于 2025-11-6 01:43
作者怎么被封啦???也没有看他刷帖啊

贴了别人的代码回复

wang2006zhi 发表于 2025-11-12 09:14:36

namespace HTJ.Arx;

/// <summary>
/// 关联动作体封装
/// BY2025.11;wang2006zhi
/// </summary>
/// <remarks>
/// 使用示例:
/// <code>
/// var logic = new Dictionary{
///    = trans => { /* 文字更新逻辑 */ },
///    = 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.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 = 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;
      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
}

wang2006zhi 发表于 2025-11-12 09:16:18

   
    public void Tt8()
    {
      if (!Env.Editor.SelId(out ObjectId circleId, RxClassEx.Circle))
            return;
      if (!Env.Editor.SelId(out ObjectId textId, RxClassEx.DbText))
            return;
      //定义联动逻辑
      var objectLogic = new Dictionary<ObjectId, Action<AssocObjectTransaction>>
      {
             = aTransaction =>
            {
                using var circle = aTransaction.GetDBObject(circleId, OpenMode.ForWrite, false, true) as Circle;
                using var text = aTransaction.GetDBObject(textId, OpenMode.ForWrite, false, true) as DBText;
                if (text is null)
                  return;
                if (circle is null)
                  return;
                text.TextString=$"{circle.Radius:F1}";
                text.ColorIndex = 2;
                text.Height = circle.Radius;
      
            },
             = aTransaction =>
            {
                using var text = aTransaction.GetDBObject(textId, OpenMode.ForWrite, false, true) as DBText;
                using var circle = aTransaction.GetDBObject(circleId, OpenMode.ForWrite, false, true) as Circle;
      
                if (text is null)
                  return;
                if (circle is null)
                  return;
                if (double.TryParse(text.TextString, out double radius))
                  circle.Radius = radius;
            }
      };
      //创建联动关联
      AssocActionEx.Create(objectLogic);

    }
页: 1 [2]
查看完整版本: 图元修改事件的封装-关联修改