替换属性块的两种方案:顺序匹配和tag匹配

按顺序匹配:

using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using System;
using System.Collections.Generic;

[assembly: CommandClass(typeof(BlockWithAttributeReplace.Commands))]

namespace BlockWithAttributeReplace
{
    public class Commands
    {
        private Editor _ed;

        [CommandMethod("ReplaceBlockWithAttributes")]
        public void ReplaceBlockWithAttributes()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            _ed = doc.Editor;

            try
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    string oldBlockName = "旧块";
                    string newBlockName = "新块";
                    int replacedCount = 0;

                    BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                    if (!bt.Has(newBlockName))
                    {
                        _ed.WriteMessage($"\n错误:新块 '{newBlockName}' 不存在");
                        return;
                    }

                    // 遍历所有块表记录(包含模型和布局空间)
                    foreach (ObjectId btrId in bt)
                    {
                        BlockTableRecord btr = tr.GetObject(btrId, OpenMode.ForRead) as BlockTableRecord;
                        if (btr.IsLayout || btr.Name == BlockTableRecord.ModelSpace) 
                        {
                            ProcessBlockReferencesInSpace(tr, btr, oldBlockName, newBlockName, ref replacedCount);
                        }
                    }

                    tr.Commit();
                    _ed.WriteMessage($"\n完成替换 {replacedCount} 个块");
                }
            }
            catch (Exception ex)
            {
                _ed.WriteMessage($"\n操作出错: {ex.Message}\n{ex.StackTrace}");
            }
        }

        private void ProcessBlockReferencesInSpace(
            Transaction tr, 
            BlockTableRecord spaceBtr, 
            string oldBlockName,
            string newBlockName,
            ref int replacedCount)
        {
            string spaceName = spaceBtr.IsLayout ? $"布局 '{spaceBtr.Name}'" : "模型空间";

            // 收集所有需要替换的块参照ID
            List<ObjectId> blockIdsToReplace = new List<ObjectId>();
            
            foreach (ObjectId objId in spaceBtr)
            {
                if (objId.ObjectClass.Name == "AcDbBlockReference")
                {
                    BlockReference br = tr.GetObject(objId, OpenMode.ForRead) as BlockReference;
                    if (br != null && br.BlockName.Equals(oldBlockName, StringComparison.OrdinalIgnoreCase))
                    {
                        blockIdsToReplace.Add(objId);
                    }
                }
            }

            foreach (ObjectId brId in blockIdsToReplace)
            {
                BlockReference oldBr = tr.GetObject(brId, OpenMode.ForRead) as BlockReference;
                if (ReplaceBlockWithAttr(oldBr, tr, newBlockName, spaceName))
                {
                    replacedCount++;
                }
            }
        }

        private bool ReplaceBlockWithAttr(BlockReference oldBr, Transaction tr, string newBlockName, string spaceName)
        {
            try
            {
                // 1. 提取旧块属性值(按顺序)
                List<string> attrValues = ExtractAttributesByOrder(oldBr, tr);
                
                // 2. 保存关键属性
                Point3d insertPoint = oldBr.Position;
                Scale3d scale = oldBr.ScaleFactors;
                double rotation = oldBr.Rotation;
                string layer = oldBr.Layer;
                ObjectId spaceId = oldBr.BlockTableRecordId;

                // 3. 删除旧块
                oldBr.UpgradeOpen();
                oldBr.Erase();

                // 4. 创建新块参照
                BlockTable bt = tr.GetObject(tr.Database.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord newBtr = tr.GetObject(bt[newBlockName], OpenMode.ForRead) as BlockTableRecord;
                
                BlockReference newBr = new BlockReference(insertPoint, newBtr.ObjectId)
                {
                    ScaleFactors = scale,
                    Rotation = rotation,
                    Layer = layer
                };

                // 5. 添加到原始空间
                BlockTableRecord currentSpace = tr.GetObject(spaceId, OpenMode.ForWrite) as BlockTableRecord;
                ObjectId newBrId = currentSpace.AppendEntity(newBr);
                tr.AddNewlyCreatedDBObject(newBr, true);

                // 6. 设置属性(按顺序)
                if (attrValues.Count > 0)
                {
                    AssignAttributesByOrder(newBr, tr, attrValues);
                }

                _ed.WriteMessage($"\n{spaceName} 成功替换块: {insertPoint}");
                return true;
            }
            catch (Exception ex)
            {
                _ed.WriteMessage($"\n{spaceName} 替换失败: {ex.Message}");
                return false;
            }
        }

        // 按顺序提取属性值(忽略标记,只记录字符串值)
        private List<string> ExtractAttributesByOrder(BlockReference br, Transaction tr)
        {
            List<string> attrValues = new List<string>();
            
            if (br.AttributeCollection.Count > 0)
            {
                foreach (ObjectId attrId in br.AttributeCollection)
                {
                    // 只处理属性参照(AttributeReference)
                    if (attrId.ObjectClass.Name == "AcDbAttribute")
                    {
                        AttributeReference attrRef = tr.GetObject(attrId, OpenMode.ForRead) as AttributeReference;
                        if (attrRef != null)
                        {
                            attrValues.Add(attrRef.TextString);
                        }
                    }
                }
            }
            return attrValues;
        }

        // 按顺序赋值属性值
        private void AssignAttributesByOrder(BlockReference newBr, Transaction tr, List<string> attrValues)
        {
            newBr.UpgradeOpen();
            
            int index = 0;
            foreach (ObjectId attrId in newBr.AttributeCollection)
            {
                // 如果已经赋值完所有旧属性,则停止
                if (index >= attrValues.Count)
                    break;

                // 只处理属性参照(AttributeReference)
                if (attrId.ObjectClass.Name == "AcDbAttribute")
                {
                    AttributeReference newAttr = tr.GetObject(attrId, OpenMode.ForWrite) as AttributeReference;
                    if (newAttr != null)
                    {
                        newAttr.TextString = attrValues[index];
                        index++;
                    }
                }
            }
        }
    }
}

按tag

using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.EditorInput;
using System;
using System.Collections.Generic;

[assembly: CommandClass(typeof(BlockWithAttributeReplace.Commands))]

namespace BlockWithAttributeReplace
{
    public class Commands
    {
        private Editor _ed;

        [CommandMethod("ReplaceBlockWithAttributes")]
        public void ReplaceBlockWithAttributes()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Database db = doc.Database;
            _ed = doc.Editor;

            try
            {
                using (Transaction tr = db.TransactionManager.StartTransaction())
                {
                    string oldBlockName = "旧块";
                    string newBlockName = "新块";
                    int replacedCount = 0;

                    BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
                    if (!bt.Has(newBlockName))
                    {
                        _ed.WriteMessage($"\n错误:新块 '{newBlockName}' 不存在");
                        return;
                    }

                    // 遍历所有块表记录(包含模型和布局空间)
                    foreach (ObjectId btrId in bt)
                    {
                        BlockTableRecord btr = tr.GetObject(btrId, OpenMode.ForRead) as BlockTableRecord;
                        if (btr.IsLayout || btr.Name == BlockTableRecord.ModelSpace) 
                        {
                            ProcessBlockReferencesInSpace(tr, btr, oldBlockName, newBlockName, ref replacedCount);
                        }
                    }

                    tr.Commit();
                    _ed.WriteMessage($"\n完成替换 {replacedCount} 个块");
                }
            }
            catch (Exception ex)
            {
                _ed.WriteMessage($"\n操作出错: {ex.Message}\n{ex.StackTrace}");
            }
        }

        private void ProcessBlockReferencesInSpace(
            Transaction tr, 
            BlockTableRecord spaceBtr, 
            string oldBlockName,
            string newBlockName,
            ref int replacedCount)
        {
            string spaceName = spaceBtr.IsLayout ? $"布局 '{spaceBtr.Name}'" : "模型空间";

            // 收集所有需要替换的块参照ID(避免在遍历时修改集合)
            List<ObjectId> blockIdsToReplace = new List<ObjectId>();
            
            foreach (ObjectId objId in spaceBtr)
            {
                if (objId.ObjectClass.Name == "AcDbBlockReference")
                {
                    BlockReference br = tr.GetObject(objId, OpenMode.ForRead) as BlockReference;
                    if (br != null && br.BlockName.Equals(oldBlockName, StringComparison.OrdinalIgnoreCase))
                    {
                        blockIdsToReplace.Add(objId);
                    }
                }
            }

            // 处理收集到的块参照
            foreach (ObjectId brId in blockIdsToReplace)
            {
                BlockReference oldBr = tr.GetObject(brId, OpenMode.ForRead) as BlockReference;
                if (ReplaceBlockWithAttr(oldBr, tr, newBlockName, spaceName))
                {
                    replacedCount++;
                }
            }
        }

        private bool ReplaceBlockWithAttr(BlockReference oldBr, Transaction tr, string newBlockName, string spaceName)
        {
            try
            {
                // 1. 提取旧块属性值
                Dictionary<string, string> attrValues = ExtractAttributes(oldBr, tr);
                
                // 2. 保存关键属性
                Point3d insertPoint = oldBr.Position; // 正确使用原始插入点
                Scale3d scale = oldBr.ScaleFactors;
                double rotation = oldBr.Rotation;
                string layer = oldBr.Layer;
                ObjectId spaceId = oldBr.BlockTableRecordId; // 原始空间ID

                // 3. 删除旧块
                oldBr.UpgradeOpen();
                oldBr.Erase();

                // 4. 创建新块参照
                BlockTable bt = tr.GetObject(tr.Database.BlockTableId, OpenMode.ForRead) as BlockTable;
                BlockTableRecord newBtr = tr.GetObject(bt[newBlockName], OpenMode.ForRead) as BlockTableRecord;
                
                BlockReference newBr = new BlockReference(insertPoint, newBtr.ObjectId)
                {
                    ScaleFactors = scale,
                    Rotation = rotation,
                    Layer = layer
                };

                // 5. 添加到原始空间
                BlockTableRecord currentSpace = tr.GetObject(spaceId, OpenMode.ForWrite) as BlockTableRecord;
                ObjectId newBrId = currentSpace.AppendEntity(newBr);
                tr.AddNewlyCreatedDBObject(newBr, true);

                // 6. 设置属性
                if (attrValues.Count > 0)
                {
                    AssignAttributes(newBr, tr, attrValues);
                }

                _ed.WriteMessage($"\n{spaceName} 成功替换块: {insertPoint}");
                return true;
            }
            catch (Exception ex)
            {
                _ed.WriteMessage($"\n{spaceName} 替换失败: {ex.Message}");
                return false;
            }
        }

        // 修复:完整属性提取方法
        private Dictionary<string, string> ExtractAttributes(BlockReference br, Transaction tr)
        {
            Dictionary<string, string> attrValues = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
            
            // 检查是否有属性集合
            if (br.AttributeCollection.Count > 0)
            {
                foreach (ObjectId attrId in br.AttributeCollection)
                {
                    if (attrId.ObjectClass.Name == "AcDbAttribute")
                    {
                        AttributeReference attrRef = tr.GetObject(attrId, OpenMode.ForRead) as AttributeReference;
                        if (attrRef != null && !string.IsNullOrWhiteSpace(attrRef.Tag))
                        {
                            attrValues[attrRef.Tag] = attrRef.TextString;
                        }
                    }
                }
            }
            return attrValues;
        }

        // 属性赋值方法
        private void AssignAttributes(BlockReference newBr, Transaction tr, Dictionary<string, string> attrValues)
        {
            newBr.UpgradeOpen();
            
            // 遍历新块的属性集合
            foreach (ObjectId attrId in newBr.AttributeCollection)
            {
                AttributeReference newAttr = tr.GetObject(attrId, OpenMode.ForWrite) as AttributeReference;
                if (newAttr != null && 
                    !string.IsNullOrWhiteSpace(newAttr.Tag) &&
                    attrValues.ContainsKey(newAttr.Tag))
                {
                    newAttr.TextString = attrValues[newAttr.Tag];
                }
            }
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山水CAD插件定制

你的鼓励是我创作最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值