将 ObjectIds 传递给方法似乎会破坏流程 - C# 中的 BURST 示例

Passing ObjectIds to method seems to break the process - BURST example in C#

我有一个模仿 BURST 命令的方法,但使用 AutoCAD 的 .NET 界面。 Select一个block,输入命令,没问题。但我想做的是将它变成一个可调用的方法,这样我就可以获得一组 ObjectIds、所有 BlockReferences,并让它一次一个地爆破它们。

我的 BURST 方法可以正常工作,并且可以证明每次调用方法时都是正确的 ObjectId。它在 .Explode 命令之后循环遍历收集到的块中的每个实体,但由于某种原因,该作品从未发布(回复:没有任何东西最终爆炸)。

我被卡住了,现在已经为此工作了几个小时,这显然超出了我的理解范围。我猜这是我忽略但看不到的一件小事。

// BURST command that bursts ALL blocks
[CommandMethod("testBurstAll")]
public void cmdTestBurstAll()
{
    // Definitions
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Editor ed = doc.Editor;
    Database db = doc.Database;

    List<ObjectId> passedObjectId = new List<ObjectId>();

    try
    {
        using (Transaction tr = db.TransactionManager.StartTransaction())
        {
            BlockTable bt = tr.GetObject(db.BlockTableId, OpenMode.ForWrite) as BlockTable;
            ObjectId oID = bt[BlockTableRecord.ModelSpace];
            BlockTableRecord btr = tr.GetObject(oID, OpenMode.ForWrite) as BlockTableRecord;
            //ed.WriteMessage("Made it to end of BT and BTR definitions");

            RXClass rxBlockRef = RXClass.GetClass(typeof(BlockReference));
            //ed.WriteMessage("Made it to RXClass definition");
            foreach (ObjectId id in btr)
            {
                if (id.IsNull || id.IsErased || id.IsEffectivelyErased || !id.IsValid)
                    continue;

                // get a list of ObjectIds for future method call
                if (id.ObjectClass == rxBlockRef)
                {
                    passedObjectId.Add(id);
                    ed.WriteMessage("\nOriginal method ObjectId: " + id.ToString());
                    /*using (BlockReference reference = tr.GetObject(id, OpenMode.ForWrite) as BlockReference)
                    {
                        ed.WriteMessage("Made it into explode");
                        
                        //reference.ExplodeToOwnerSpace();
                        reference.Erase();
                        //ed.WriteMessage("Made it past explode");
                    }*/
                }
            }

            // Call BURST method for each BlockReference ObjectId added to list
            for( int i = 0; i < passedObjectId.Count; i++)
            {
                cmdTestBurstMethod(passedObjectId.ElementAt(i));
            }
        }
    }
    catch 
    {
        ed.WriteMessage("CATCH used, exception caught");
    }
}

// BURST method - to be called by other commands - needs an ObjectID as input
public void cmdTestBurstMethod(ObjectId passedId)
{
    Document doc = Application.DocumentManager.MdiActiveDocument;
    Database db = doc.Database;
    Editor ed = doc.Editor;
    //ed.WriteMessage("\nMade it into BURST method call with: " + passedId.ToString());

    using (Transaction tr = db.TransactionManager.StartTransaction())
    {
        ObjectId msId = SymbolUtilityServices.GetBlockModelSpaceId(db);
        BlockTableRecord ms = tr.GetObject(msId, OpenMode.ForWrite) as BlockTableRecord;

        BlockReference blockRef = tr.GetObject(passedId, OpenMode.ForRead) as BlockReference;

        ed.WriteMessage("\nInto BURST method with OjbectId: " + blockRef.ObjectId.ToString());
        if (blockRef != null)
        {
            DBObjectCollection toAddColl = new DBObjectCollection();
            BlockTableRecord blockDef = tr.GetObject(blockRef.BlockTableRecord, OpenMode.ForRead) as BlockTableRecord;

            // Create a text for const and visible attributes 
            foreach (ObjectId entId in blockDef)
            {
                if (entId.ObjectClass.Name == "AcDbAttributeDefinition")
                {
                    AttributeDefinition attDef = tr.GetObject(entId, OpenMode.ForRead) as AttributeDefinition;

                    if ((attDef.Constant && !attDef.Invisible))
                    {
                        DBText text = new DBText();
                        text.Height = attDef.Height;
                        text.TextString = attDef.TextString;
                        text.Position = attDef.Position.TransformBy(blockRef.BlockTransform);
                        toAddColl.Add(text);
                    }
                }
            }

            // Create a text for non-const and visible attributes 
            foreach (ObjectId attRefId in blockRef.AttributeCollection)
            {
                AttributeReference attRef = tr.GetObject(attRefId, OpenMode.ForRead) as AttributeReference;

                if (attRef.Invisible == false)
                {
                    DBText text = new DBText();
                    text.Height = attRef.Height;

                    text.TextString = attRef.TextString;
                    text.Position = attRef.Position;
                    toAddColl.Add(text);
                }
            }
            
            // Get the entities from the block reference Attribute definitions have been taken care of.. so ignore them 
            DBObjectCollection entityColl = new DBObjectCollection();
            blockRef.Explode(entityColl);

            // Get Layer of existing Block and move any objects in that block to the existing layer of the Block (anything on layer '0')
            ed.WriteMessage("\nblockRef NOT NULL");
            String exLayer = blockRef.Layer;
            foreach (Entity ent in entityColl)
            {
                ed.WriteMessage("\nForEach loop entered with: " + ent.ObjectId.ToString());
                if (!(ent is AttributeDefinition))
                {
                    ed.WriteMessage("\nEntered IF !AttributeDefinition");
                    if (ent.Layer == "0")
                    {
                        ed.WriteMessage("\nEntered IF on Layer zero");
                        ent.Layer = exLayer;
                    }
                    toAddColl.Add(ent);
                }
            }
            // Add the entities to modelspace 
            foreach (Entity ent in toAddColl)
            {
                ms.AppendEntity(ent);
                tr.AddNewlyCreatedDBObject(ent, true);
            }
            // Erase the block reference 
            blockRef.UpgradeOpen();
            blockRef.Erase();
        }
        tr.Commit();
    }
}

没有展开任何内容,因为未提交父事务。
所以每个子事务都会回滚。
避免为每个 ObjectId 启动新的子事务的一种方法是将父事务作为参数传递。
然后在顶层方法中提交父事务,在突发之后。

这是一个简单粗暴的例子:

    [CommandMethod("TEST")]
    public static void Test()
    {
        var doc = Application.DocumentManager.MdiActiveDocument;
        var db = doc.Database;
        var ed = doc.Editor;
        using (var tr = db.TransactionManager.StartTransaction())
        {
            var modelSpace = (BlockTableRecord)tr.GetObject(
                SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForWrite);
            var brClass = RXObject.GetClass(typeof(BlockReference));
            var ids = modelSpace
                .Cast<ObjectId>()
                .Where(id => id.ObjectClass == brClass);
            foreach (ObjectId id in ids)
            {
                Burst(id, modelSpace, tr);
            }
            tr.Commit();
        }
    }

    private static void Burst(ObjectId id, BlockTableRecord owner, Transaction tr)
    {
        var br = (BlockReference)tr.GetObject(id, OpenMode.ForWrite);
        foreach (ObjectId attId in br.AttributeCollection)
        {
            var attRef = (AttributeReference)tr.GetObject(attId, OpenMode.ForWrite);
            CreateTextFromAttrib(attRef, br.Layer, owner, tr);
            attRef.Erase();
        }
        var entities = new DBObjectCollection();
        br.Explode(entities);
        foreach (Entity entity in entities)
        {
            if (entity is AttributeDefinition)
            {
                var attDef = (AttributeDefinition)entity;
                if (attDef.Constant)
                {
                    CreateTextFromAttrib(attDef, br.Layer, owner, tr);
                }
                entity.Dispose();
            }
            else
            {
                if (entity.Layer == "0") entity.Layer = br.Layer;
                if (entity.ColorIndex == 0) entity.ColorIndex = 256;
                owner.AppendEntity(entity);
                tr.AddNewlyCreatedDBObject(entity, true);
            }
        }
        br.Erase();
    }

    private static void CreateTextFromAttrib(DBText att, string layer, BlockTableRecord owner, Transaction tr)
    {
        var text = new DBText
        {
            Rotation = att.Rotation,
            TextString = att.TextString,
            Height = att.Height,
            Justify = att.Justify,
            Position = att.Position
        };
        text.SetPropertiesFrom(att);
        if (att.Justify != AttachmentPoint.BaseLeft)
        {
            text.AlignmentPoint = att.AlignmentPoint;
        }
        if (text.Layer == "0") text.Layer = layer;
        if (text.ColorIndex == 0) text.ColorIndex = 256;
        owner.AppendEntity(text);
        tr.AddNewlyCreatedDBObject(text, true);
    }