Copy Block From file to file

Copy Block From file to file

micle.space
Enthusiast Enthusiast
6,502 Views
18 Replies
Message 1 of 19

Copy Block From file to file

micle.space
Enthusiast
Enthusiast

After several days of coding and researchs, i have to require an help due to the very poor results reached up to now, so here you are my frst post.
I have a very huge directory archive with several DWG drawings.

Each drawing in these directories has a block named "OldBlock" with some attributes: Attrib1, Attib2, Attrib3....(the block is always the same, the attributes TAG are always the same, the attributes values change from file to file)

I have to replace, in each dwg file, this "OldBlock" with a new one named "NewBlock" and put the values of attributes of he old block to the new one.

Other Conditions:
- The OldBlock is on a certain paper_space of dwg drawing so the NewBlock must have the same location and position.
- the OldBlock has to be delete.
- The NewBlock is in a dwg file named "SourceDwgFile"


I have very clear the steps I need for the whole routine, but I cannot recognize the right hierarchy of blockTable, how identify the attributes, how manage transction and so on...

I would prefer coding with C# but VB could be suitble.
Could someone direct me to on the right road?

0 Likes
Accepted solutions (1)
6,503 Views
18 Replies
Replies (18)
Message 2 of 19

Anonymous
Not applicable

Not a solution, but maybe a start.... 

Database acCurDb = _document.Database;

using (Transaction acTrans = acCurDb.TransactionManager.StartOpenCloseTransaction())
{
// Open the Block table record for read
var acBlkTbl = acTrans.GetObject(acCurDb.BlockTableId, OpenMode.ForRead) as BlockTable;

// Open the Block table record Paper space for read
var acBlkTblRec = acTrans.GetObject(acBlkTbl[BlockTableRecord.PaperSpace], OpenMode.ForRead) as BlockTableRecord;

// Step through each object in Model space and
// display the type of object found
foreach (var acObjId in acBlkTblRec)
{
var br = acTrans.GetObject(acObjId, OpenMode.ForRead) as BlockReference;

if (br != null)
{
// tags you are interested in...
var taglist = new string[] {"CAT", "CAT01", "CAT02", "CAT03"};
foreach (var t in taglist)
{

// Your copying code....

}
br.Dispose();
}
}
acBlkTbl.Dispose();
acBlkTblRec.Dispose();
}

Some hints at what you could do:

 

_document is Snippet

Autodesk.AutoCAD.ApplicationServices.Core.Application.DocumentManager.MdiActiveDocument

 So have a second one for copying to.  You would have to find out how to create new or copy block references from one to the other and populate attrs in new document.

0 Likes
Message 3 of 19

ActivistInvestor
Mentor
Mentor

@micle.space wrote:

After several days of coding and researchs, i have to require an help due to the very poor results reached up to now, so here you are my frst post.
I have a very huge directory archive with several DWG drawings.

Each drawing in these directories has a block named "OldBlock" with some attributes: Attrib1, Attib2, Attrib3....(the block is always the same, the attributes TAG are always the same, the attributes values change from file to file)

I have to replace, in each dwg file, this "OldBlock" with a new one named "NewBlock" and put the values of attributes of he old block to the new one.

Other Conditions:
- The OldBlock is on a certain paper_space of dwg drawing so the NewBlock must have the same location and position.
- the OldBlock has to be delete.
- The NewBlock is in a dwg file named "SourceDwgFile"


I have very clear the steps I need for the whole routine, but I cannot recognize the right hierarchy of blockTable, how identify the attributes, how manage transction and so on...

I would prefer coding with C# but VB could be suitble.
Could someone direct me to on the right road?


If you've attempted to write code to do this and it isn't working, you should post the code and then you might get some help with it. 

 

 

0 Likes
Message 4 of 19

micle.space
Enthusiast
Enthusiast

Dear all, first of all thank you for your attention.

Here a frame of routine I would like to execute.

 

The idea is:

1 - store a BlockTableRecord btSource from the new file with the new block.

2 - Foreach file in directories:

  • find the old block (blockToBeReplaced)
  • keep position and attributes values from the old block and save them into btSource
  • Remove from the file the old block
  • Store in the file the new one
  • Save file.

cheers

M.

 

  

 

 

        [CommandMethod("BREP")]
        public void BlockReplace()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;

            string[] allDwgFiles = Directory.GetFiles("dwgFilesToBeReplaced", "*.dwg", SearchOption.AllDirectories);

            //set the source database
            Database sourceDb = new Database(false, true);
            sourceDb.ReadDwgFile(dwgSourcePath, System.IO.FileShare.Read, false, "");
            BlockTableRecord sourceTbr;

            using (Transaction tr = sourceDb.TransactionManager.StartOpenCloseTransaction())
            {
                //Table record
                BlockTable btSource = (BlockTable)tr.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
               
                foreach (ObjectId objId in btSource)
                {
                    BlockTableRecord btrSource = (BlockTableRecord)tr.GetObject(objId, OpenMode.ForRead);
                    if (btrSource.Name == blockNew)
                    {
                        sourceTbr = (BlockTableRecord)btrSource.Clone();
                    }
                }
                tr.Commit();
            }

            //replace the block in each file
            foreach (string currDwg in allDwgFiles)
            {
                //open the file
                Database currDb = new Database(false, true);
                currDb.ReadDwgFile(dwgSourcePath, System.IO.FileShare.ReadWrite, false, "");

                using (Transaction tr = currDb.TransactionManager.StartTransaction())
                {
                    //open the block in the current file
                    BlockTable currBt = (BlockTable)tr.GetObject(currDb.BlockTableId, OpenMode.ForRead);
                    
                    //research of old block
                    foreach (ObjectId objId in currBt)
                    {
                        BlockTableRecord currBtr = (BlockTableRecord)tr.GetObject(objId, OpenMode.ForRead);
                        if (currBtr.Name == blockToBeReplaced)
                        {
                            //references from source block
                            BlockReference sourceRef = sourceTbr as BlockReference; //????

                            //fill the source database with the attributes
                            BlockReference currBlkRef = (BlockReference)objId.GetObject(OpenMode.ForRead);
                            AttributeCollection currAttColl = currBlkRef.AttributeCollection;

                            //set the position of the block
                            sourceRef.Position = currBlkRef.Position;
                            
                            //set the attributes
                            foreach (ObjectId id in currAttColl)
                            {
                                DBObject dbObj = (DBObject)tr.GetObject(id, OpenMode.ForRead);
                                AttributeReference attRef = dbObj as AttributeReference;
                                sourceRef[attRef.Tag] = attRef.TextString; //?????
                            }

                        }
                    }
                    //filled the btrSource with old values, I provide o replace the old block with the new one.
                    BlockTableRecord currBtr = (BlockTableRecord)tr.GetObject(currBt.ObjectId, OpenMode.ForWrite);
                    currBtr.RemoveOldBlock......;       //<<< how could I do it?
                    currBtr.AppendEntity(sourceTbr);    //Append new block ... how Could I do it?

                    //Save and close current file ---> how?

                    tr.Commit();

                }
            }
        }
0 Likes
Message 5 of 19

micle.space
Enthusiast
Enthusiast

new frustration day...  zero results, I can just copy the block in the file, but cannot put it on the desidered layout...

 

        public static void AddNewBlock(Database dbDest, ObjectId newBlk)
        {
            using (Transaction tr = dbDest.TransactionManager.StartTransaction())
            {
                //block Table detination
                BlockTable btDest = (BlockTable)tr.GetObject(dbDest.BlockTableId, OpenMode.ForWrite);

                //blocktableSorse                
                BlockTableRecord newBtr = (BlockTableRecord)newBlk.GetObject(OpenMode.ForRead);
                Database sourceDb = newBtr.Database;

                //open a new transaction and get the blocktable
                BlockTable newBt = null;
                using (Transaction trNew = sourceDb.TransactionManager.StartTransaction())
                {
                    newBt = (BlockTable)trNew.GetObject(sourceDb.BlockTableId, OpenMode.ForRead);
                    trNew.Commit();
                }
                    


                //layout of target file 
                DBDictionary layDic = (DBDictionary)tr.GetObject(dbDest.LayoutDictionaryId, OpenMode.ForRead);

                ////colection of obj to copy in the file
                ObjectIdCollection objColl = new ObjectIdCollection();

                //I want put my object in each layout of target drawing so:
                foreach (DBDictionaryEntry entry in layDic)
                {
                    if (entry.Key != "Model")
                    {
                        Layout lay = (Layout)tr.GetObject(entry.Value, OpenMode.ForRead);
                        BlockTableRecord btrLay = (BlockTableRecord)tr.GetObject(lay.BlockTableRecordId, OpenMode.ForWrite);
                        BlockReference br = new BlockReference(new Point3d(0, 0, 0), newBt["CartiglioA4_Baschild_Rev1"]);                        
                        objColl.Add(br.ObjectId);
                        //btrLay.AppendEntity(br);
                        //tr.AddNewlyCreatedDBObject(br, true);
                    }
                }

                if (objColl == null)
                {
                    throw new System.Exception("Collecion Null");
                }

                //here exception for objectnull
                if (!btDest.Has(newBtr.Name)) 
                {
                    IdMapping map = new IdMapping(); 
                    sourceDb.WblockCloneObjects(objColl, btDest.ObjectId, map, DuplicateRecordCloning.Replace, false);
                }
                tr.Commit();
            }
        }

What can I do?

0 Likes
Message 6 of 19

norman.yuan
Mentor
Mentor

While you said you have "very clear steps", your code shown in your later post says otherwise. 

 

In your latest posted code, you are trying to copy/place BlockReference from source drawing into BlockTable of the destination drawing, which would fail for sure.

 

The process itself, as you described, is not too complicated: the 2 main tasks are to identify BlockReferences to be replaced, and import/insert/identify a new block definition (BlockTableRecord) into the drawing, so that you can create new BlockReferencesto replace the existing ones.

 

For the first one, you can either loop through each layout to find BlockReferences with that name (if it is dynamic block, extra attention is needed, regarding its name). Or you can simply use Editor.SelectAll with proper filter to select all block refernces regardless layout (assume the drawing is opened in AutoCAD editor).

 

For the second task, it is not very clear fromo your description: is the source drawing a NewBlock itself, or is the NewBlock one of the block definitions stored in source drawing? If it is the former, then ut is very simple: you simply insert this drawing as block definition; if it is latter, then you indeed need to WBlockCloneObjects() this block defeinition (BlockTableRecord!) from the source drawing into destination drawing's BlockTable.

 

So here is the pseudo-code of what you do:

 

 

For each DrawingFileName in DrawingFileNameList

 

  Open the drawing in AutoCAD/Or oepn the drawing as side database

  Test if the NewBlock definition exists.

  If NewBlock definition is ot found Then

    Database.Insert()/SourceDatabase.WblockCloneObjects() //depending on the source drawing

  End

  Search drawing/DB for the OldBlock to get a list of ObjectId (of the OldBlock references

  For each oldBlock Id in olbBlockIds

    Open the oldBlockrefernce to obtain attribute values, keyed by attribute tags, and its position

    Insert blockreferences of NewBlock at the position, set its attributes

    Delete the pldBlock reference

  Next

  Savethe drawing/DB, and close it

 

Next

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 7 of 19

micle.space
Enthusiast
Enthusiast

Thank you Norman, you are right, I'm bit confuse (due to the low knoweledge of hierarchy autocad class) , this is my first program and it is not my job... but I would like to socceed.

in these days with a bit of your suggestions and a bit other researchs on the web I got some results but the routine is not working properly yet.

I wonder if could be possible have the same approach of your suggestion and research by layout.

Following the pseudo-code:

 

For each DrawingFileName in DrawingFileNameList

 

  Open the drawing in AutoCAD/Or oepn the drawing as side database

  Test if the NewBlock definition exists.

  If NewBlock definition is not found Then   <<<<<This search has to be done for each Layout (not for Model_Space)

    Database.Insert()/SourceDatabase.WblockCloneObjects() //depending on the source drawing

  End

  Search drawing/DB for the OldBlock to get a list of ObjectId (of the OldBlock references

  For each oldBlock Id in olbBlockIds       

    Open the oldBlockrefernce to obtain attribute values, keyed by attribute tags, and its position

    Insert blockreferences of NewBlock at the position, set its attributes

    Delete the pldBlock reference

  Next

  Savethe drawing/DB, and close it

 

Next

 

Thanks in advance for supports and advices.

 

0 Likes
Message 8 of 19

norman.yuan
Mentor
Mentor

@micle.space wrote:

Thank you Norman, you are right, I'm bit confuse (due to the low knoweledge of hierarchy autocad class) , this is my first program and it is not my job... but I would like to socceed.

in these days with a bit of your suggestions and a bit other researchs on the web I got some results but the routine is not working properly yet.

I wonder if could be possible have the same approach of your suggestion and research by layout.

Following the pseudo-code:

 

For each DrawingFileName in DrawingFileNameList

 

  ......

  If NewBlock definition is not found Then   <<<<<This search has to be done for each Layout (not for Model_Space)

    Database.Insert()/SourceDatabase.WblockCloneObjects() //depending on the source drawing

  End

  ......

 

Next

 


Block definition (BlockTableRecord) is "per database" (per drawing), not "per layout"!

 

It is the next step (searching "OldBlock" references to be replaced where you may want to limit the search on specific layout.

Norman Yuan

Drive CAD With Code

EESignature

0 Likes
Message 9 of 19

ActivistInvestor
Mentor
Mentor

@norman.yuan wrote:

@micle.space wrote:

Thank you Norman, you are right, I'm bit confuse (due to the low knoweledge of hierarchy autocad class) , this is my first program and it is not my job... but I would like to socceed.

in these days with a bit of your suggestions and a bit other researchs on the web I got some results but the routine is not working properly yet.

I wonder if could be possible have the same approach of your suggestion and research by layout.

Following the pseudo-code:

 

For each DrawingFileName in DrawingFileNameList

 

  ......

  If NewBlock definition is not found Then   <<<<<This search has to be done for each Layout (not for Model_Space)

    Database.Insert()/SourceDatabase.WblockCloneObjects() //depending on the source drawing

  End

  ......

 

Next

 


Block definition (BlockTableRecord) is "per database" (per drawing), not "per layout"!

 

It is the next step (searching "OldBlock" references to be replaced where you may want to limit the search on specific layout.


You can get the ObjectIds of all insertions of a block in a drawing from the BlockTableRecord's GetBlockReferenceIds() method.

 

 

0 Likes
Message 10 of 19

norman.yuan
Mentor
Mentor

I happened to have a bit time, so, I put together a chunk of code that works in following condition:

 

1. 2 target drawings to be processed. Each has a few block references named as "OldBlock" inserted on various layouts. The "OldBlock" has a few attributes"; and the block is not dynamic block (so, when searching block references, the code only compare BlockReference.Name is equal "OldBlock" or not).

 

2. The block used to replace "OldBlock" references existing in target drawings is named as "NewBlock", which has the same set of attributes (i.e. the attributes have the same tags); "NewBlock" is not defined in target drawings; "NewBlock" exists as a block drawing file.

 

3. The code open the target drawing as side database (not opening it in AutoCAD editor visibly). 

 

4. To find existing "OldBlock" references, I simply loop through all Layout blocks. It can also be done in other ways, such as firstly find the "OldBlock" definition, and call its GetBlockReferenceIds(), and then traces back to the block reference's owner block, thus the layout...

 

Here is the code that works well:

 

using System.Collections.Generic;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Geometry;
using CadApp = Autodesk.AutoCAD.ApplicationServices.Application;

[assembly: CommandClass(typeof(ReplaceBlocks.MyCommands))]

namespace ReplaceBlocks
{
    internal class BlockAttributeData
    {
        public ObjectId BlkRefId { set; get; }
        public string Layer { set; get; }
        public Dictionary<string, string> Attributes { private set; get; }

        internal BlockAttributeData()
        {
            BlkRefId = ObjectId.Null;
            Attributes = new Dictionary<string, string>();
        }
    }

    internal class DrawingAttributeData : Dictionary<ObjectId, IEnumerable<BlockAttributeData>>
    {

    }

    public class MyCommands
    {
        [CommandMethod("ReplaceBlk")]
        public static void RunDocCommand()
        {
            string[] dwgFiles = new string[]
            {
                @"C:\Users\norman.yuan\Documents\Visual Studio 2017\Projects\AutoCAD2017\ReplaceBlocks\TestDwgs\TestDrawingA.dwg",
                @"C:\Users\norman.yuan\Documents\Visual Studio 2017\Projects\AutoCAD2017\ReplaceBlocks\TestDwgs\TestDrawingB.dwg"
            };

            string newBlockFile = 
                @"C:\Users\norman.yuan\Documents\Visual Studio 2017\Projects\AutoCAD2017\ReplaceBlocks\TestDwgs\NewBlock.dwg";

            var workingDb = HostApplicationServices.WorkingDatabase;
            
            try
            {
                foreach (var dwgfile in dwgFiles)
                {
                    // Open target drawing as side database.
                    // It makes the processing a lot faster than opening
                    // drawing in Editor visibly.
                    // One can choose open the drawing in Editor, if desired.
                    using (var db = OpenSideDatabase(dwgfile))
                    {
                        HostApplicationServices.WorkingDatabase = db;
                        ReplaceBlocks(db, "OldBlock", "NewBlock", newBlockFile);
                        db.SaveAs(dwgfile, true, DwgVersion.Current, null);
                    }
                }
            }
            catch (System.Exception ex)
            {
                CadApp.ShowAlertDialog("Error:\r\n" + ex.Message);
            }
            finally
            {
                HostApplicationServices.WorkingDatabase = workingDb;
                Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt();
            }
        }

        private static Database OpenSideDatabase(string dwgFileName)
        {
            var db = new Database(false, true);
            db.ReadDwgFile(
                dwgFileName, FileOpenMode.OpenForReadAndWriteNoShare, false, null);
            return db;
        }

        private static void ReplaceBlocks(
            Database db, string oldBlkName, string newBlkName, string newBlockFile)
        {
            // Find all "OldBlock" references and collect their attribute data
            // If only blockreference on certain layout is targeted, this is where
            // one can decide which layout to be excluded
            var dwgAttData = CollectOldBlockAttributeData(db, oldBlkName);
            if (dwgAttData.Count==0)
            {
                CadApp.ShowAlertDialog("No \"" + oldBlkName + "\" found!");
                return;
            }

            // Make sure "NewBlock" is defined in the drawing. If not, get it from 
            // a block drawing file (Database.Insert(); or the the block definition
            // is in a drawing where many blocks are defined, use 
            // use Database.WblockCloneObjects() to bring this block definition
            // into this drawing
            var newBlkDefId = EnsureNewBlockDefinition(db, newBlkName, newBlockFile);
            if (newBlkDefId.IsNull)
            {
                CadApp.ShowAlertDialog(
                    "NewBlock definition is not found in source drawing!");
                return;
            }

            // Replacing "OldBlock" references by
            // 1. Insert "NewBlock" at the same position/same layer
            // 2. Sych  attribute values (because both old and new blocks have the same Attrs.
            // 3. Erase "OldBlock" reference
            ReplaceOldBlocks(db, newBlkDefId, dwgAttData);

        }

        #region find all "OldBlock" and their attribute information
        private static DrawingAttributeData CollectOldBlockAttributeData(
            Database db, string oldBlkName)
        {
            var attData = new DrawingAttributeData();

            using (var tran = db.TransactionManager.StartTransaction())
            {
                var dic = (DBDictionary)tran.GetObject(
                    db.LayoutDictionaryId, OpenMode.ForRead);
                foreach (DBDictionaryEntry entry in dic)
                {
                    var layout = (Layout)tran.GetObject(entry.Value, OpenMode.ForRead);
                    var layoutAttData = CollectOldBlockAttributeDataOnLayout(
                        oldBlkName, layout.BlockTableRecordId, tran);
                    if (layoutAttData.Count > 0)
                    {
                        attData.Add(layout.BlockTableRecordId, layoutAttData);
                    }
                }

                tran.Commit();
            }
            
            return attData;
        }

        private static List<BlockAttributeData> CollectOldBlockAttributeDataOnLayout(
            string oldBlkName, ObjectId layoutBlockId, Transaction tran)
        {
            var layoutAttData = new List<BlockAttributeData>();

            var layoutBlock = (BlockTableRecord)tran.GetObject(layoutBlockId, OpenMode.ForRead);
            foreach (ObjectId id in layoutBlock)
            {
                if (id.ObjectClass.DxfName.ToUpper()=="INSERT")
                {
                    var blk = (BlockReference)tran.GetObject(id, OpenMode.ForRead);
                    if (blk.Name.ToUpper()==oldBlkName.ToUpper())
                    {
                        var blkAttData = CollectOldBlockAttributes(blk, tran);
                        if (blkAttData.Attributes.Count > 0)
                        {
                            layoutAttData.Add(blkAttData);
                        }
                    }
                }
            }

            return layoutAttData;
        }

        private static BlockAttributeData CollectOldBlockAttributes(
            BlockReference bref, Transaction tran)
        {
            var blkAttData = new BlockAttributeData();
            blkAttData.BlkRefId = bref.ObjectId;
            blkAttData.Layer = bref.Layer;

            foreach (ObjectId id in bref.AttributeCollection)
            {
                var att = (AttributeReference)tran.GetObject(id, OpenMode.ForRead);
                if (att.IsConstant) continue;

                if (!blkAttData.Attributes.ContainsKey(att.Tag.ToUpper()))
                {
                    blkAttData.Attributes.Add(att.Tag.ToUpper(), att.TextString);
                }
            }

            return blkAttData;
        }

        #endregion

        #region make sure "NewBlock" definition exists

        private static ObjectId EnsureNewBlockDefinition(
            Database db, string newBlkName, string newBlockFile)
        {
            var blkId = ObjectId.Null;

            using (var tran=db.TransactionManager.StartTransaction())
            {
                var bt = 
                    (BlockTable)tran.GetObject(db.BlockTableId, OpenMode.ForRead);
                if (bt.Has(newBlkName)) blkId = bt[newBlkName];
                tran.Commit();
            }

            if (blkId.IsNull)
            {
                blkId = InsertNewBlockDefinition(db, newBlkName, newBlockFile);
            }

            return blkId;
        }

        private static ObjectId InsertNewBlockDefinition(
            Database db, string blkName, string blkFile)
        {
            var blkId = ObjectId.Null;
            using (var blkDb = new Database(false, true))
            {
                blkDb.ReadDwgFile(
                    blkFile, FileOpenMode.OpenForReadAndReadShare, false, null);
                blkId = db.Insert(blkName, blkDb, false);
            }
            return blkId;
        }

        #endregion

        #region do the replacing work

        private static void ReplaceOldBlocks(
            Database db, ObjectId newBlkDefId, 
            DrawingAttributeData dwgAttData)
        {
            using (var tran = db.TransactionManager.StartTransaction())
            {
                foreach (var item in dwgAttData)
                {
                    var layoutBlock = 
                        (BlockTableRecord)tran.GetObject(item.Key, OpenMode.ForWrite);
                    var newBlock = 
                        (BlockTableRecord)tran.GetObject(newBlkDefId, OpenMode.ForRead);

                    foreach (var blkData in item.Value)
                    {
                        var oldBlk = 
                            (BlockReference)tran.GetObject(blkData.BlkRefId, OpenMode.ForRead);
                        var position = oldBlk.Position;

                        CreateNewBlockReference(
                            db, layoutBlock, newBlock, 
                            position, blkData.Layer, 
                            blkData.Attributes, tran);

                        oldBlk.UpgradeOpen();
                        oldBlk.Erase();
                    }
                }

                tran.Commit();
            }
        }

        private static void CreateNewBlockReference(
            Database db, BlockTableRecord layoutBlock, 
            BlockTableRecord newBlock, Point3d position, 
            string layer, Dictionary<string, string> attData, 
            Transaction tran)
        {
            var bref = new BlockReference(position, newBlock.ObjectId);
            bref.SetDatabaseDefaults(db);
            bref.Layer = layer;

            var brefId = layoutBlock.AppendEntity(bref);
            tran.AddNewlyCreatedDBObject(bref, true);

            SetAttributes(brefId, newBlock, attData, tran);
        }

        private static void SetAttributes(
            ObjectId brefId, BlockTableRecord newBlock, 
            Dictionary<string, string> attData, Transaction tran)
        {
            var bref = (BlockReference)tran.GetObject(brefId, OpenMode.ForWrite);

            foreach (ObjectId id in newBlock)
            {
                var attDef = tran.GetObject(id, OpenMode.ForRead) as AttributeDefinition;
                if (attDef!=null)
                {
                    var att = new AttributeReference();
                    att.SetAttributeFromBlock(attDef, bref.BlockTransform);
                    if (!attDef.Constant)
                    {
                        if (attData.ContainsKey(att.Tag.ToUpper()))
                        {
                            att.TextString = attData[att.Tag.ToUpper()];
                        }
                    }

                    bref.AttributeCollection.AppendAttribute(att);
                    tran.AddNewlyCreatedDBObject(att, true);
                }
            }
        }

        #endregion
    }
}

HTH

Norman Yuan

Drive CAD With Code

EESignature

Message 11 of 19

micle.space
Enthusiast
Enthusiast

belive it or not, tomorrow is my birthday and for sure this is the best present.

Thanks Norman, I guess to learn it and test it within this week and I will give you a response quickly!

0 Likes
Message 12 of 19

fieldguy
Advisor
Advisor

happy birthday!

0 Likes
Message 13 of 19

micle.space
Enthusiast
Enthusiast

Thanks for wishes!

Concerning the prg posted by Norman, I can say it works well although didn't start at first run.

The misurandestending is in:

 

db.insert(...)

 

        private static ObjectId InsertNewBlockDefinition(
            Database db, string blkName, string blkFile)
        {
            var blkId = ObjectId.Null;
            using (var blkDb = new Database(false, true))
            {
                blkDb.ReadDwgFile(
                    blkFile, FileOpenMode.OpenForReadAndReadShare, false, null);
                blkId = db.Insert(blkName, blkDb, false);
            }
            return blkId;
        }

 

I had to change with "WblockCloneObjects" method in order to avoid an exception.

The matter is easy to solve and than the routine works well (thanks Norman again).

cheers and...... to the next week!

 

0 Likes
Message 14 of 19

ActivistInvestor
Mentor
Mentor

@micle.space wrote:

Thanks for wishes!

Concerning the prg posted by Norman, I can say it works well although didn't start at first run.

The misurandestending is in:

 

db.insert(...)

 

        private static ObjectId InsertNewBlockDefinition(
            Database db, string blkName, string blkFile)
        {
            var blkId = ObjectId.Null;
            using (var blkDb = new Database(false, true))
            {
                blkDb.ReadDwgFile(
                    blkFile, FileOpenMode.OpenForReadAndReadShare, false, null);
                blkId = db.Insert(blkName, blkDb, false);
            }
            return blkId;
        }

 

I had to change with "WblockCloneObjects" method in order to avoid an exception.

The matter is easy to solve and than the routine works well (thanks Norman again).

cheers and...... to the next week!

 


After seeing the code @norman.yuan posted, I think I should mention that you can also just redefine the block definition in the drawings in which you need to replace the block references, rather than replace the block references and add another block definition. If you need to modify the attributes and they have the same number and tags as the block that's being replaced, you can do that after the fact, by just modifying the existing insertions and their attributes, rather than replacing them.

 

I have written quite a bit of code that does batch replacement of block definitions, by just redefining the block in each target drawing, because that's essentially the same as replacing the references with references to another newly-inserted block. If need be, the modified block definition's name can be changed to name of the block that is to replace it. What you end up with is essentially the same thing, but without having to replace all of the block references.

 

If you want to change the block that an existing block insertion references, you can just set the BlockReference's BlockTableRecord property to the ObjectId of the BlockTableRecord representing the block that it should reference. That preserves all of the existing insertions, attributes, and their properties (Norman's code only replicates the Layer and Insertion point).

 

For example, if attributes had been edited and moved from their default positions, replacing the block reference and its attributes with a new BlockReference and new attributes would not preserve any changes made to the existing attributes of the insertion that's being replaced.

 

Another mistake that a lot of code I see that does batch processing of drawing files without opening them in the editor, is that merely calling SaveAs() causes the resulting DWG file to loose its thumbnail preview, unless you first set the Database's RetainOriginalThumbnailBitmap property to true.

Message 15 of 19

micle.space
Enthusiast
Enthusiast

 

@ActivistInvestor, thank you for your time, for sure you point out some question could be worthwhile to examine in depth, however without detracting anything to the frame written by @norman.yuan, it remains a good start and useful for my purpose.

 

From your post:

"I have written quite a bit of code that does batch replacement of block definitions, ...."

Could you provide a sample or where to find it?

 

"...That preserves all of the existing insertions, attributes, and their properties..."

Is this true also for fields? (please thake a look to: https://knowledge.autodesk.com/support/autocad/learn-explore/caas/CloudHelp/cloudhelp/2016/ENU/AutoC... in order to understand what I mean). The routine loses fields of old block in the new one.

 

"For example, if attributes had been edited and moved from their default positions, replacing the block reference and its attributes with a new BlockReference and new attributes would not preserve any changes made to the existing attributes of the insertion that's being replaced."

Yes it,s true, and for this reason I was going to replace only some fields and avoid the copy from old block to new one of those are in common and same.

 

"....calling SaveAs() causes the resulting DWG file to loose its thumbnail preview, unless you first set the Database's RetainOriginalThumbnailBitmap property to true"

Interesting, I noted it (thinking just to a bug), I will try to set it to true.

 

Cheers

M.

 

0 Likes
Message 16 of 19

ActivistInvestor
Mentor
Mentor

@micle.space wrote:

 

Could you provide a sample or where to find it?

  


Unfortunately, most of that code was written under contract, which means I'm not able to distribute it as-is. Other code I do have which is not subject to that restriction has a great number of dependencies on other code that would make it difficult to provide as a 'sample', without a lot of baggage. If I can find something that shows the basic concept and doesn't have too many dependencies, I will post it.

 


@micle.space wrote:

 

 

"...That preserves all of the existing insertions, attributes, and their properties..."

Is this true also for fields? (please thake a look to: https://knowledge.autodesk.com/support/autocad/learn-explore/caas/CloudHelp/cloudhelp/2016/ENU/AutoC... in order to understand what I mean). The routine loses fields of old block in the new one.

 

 


Yes, because you're not deleting an existing BlockReference and replacing it with a new one, so everything that exists, including fields remains intact, but only if you don't modify the existing attributes. If you have to modify the attributes and they contain fields, then it becomes a bit more complicated.


@micle.space wrote:

 

"For example, if attributes had been edited and moved from their default positions, replacing the block reference and its attributes with a new BlockReference and new attributes would not preserve any changes made to the existing attributes of the insertion that's being replaced."

Yes it,s true, and for this reason I was going to replace only some fields and avoid the copy from old block to new one of those are in common and same.

  


Regarding fields, it depends on whether a field has a reference to other objects in the drawing. If they do, the fields can't be simply be copied from the source database to the new one, without doing a deep-clone operation that also includes the object(s) that are referenced by the fields. So, how complicated it can be depends on the nature and type of fields used. For example, if fields reference custom DWG properties (a fairly-typical use case), the custom DWG properties must exist in the destination database.

0 Likes
Message 17 of 19

micle.space
Enthusiast
Enthusiast
Accepted solution

After several days, I can say I have reached a solution (yes I can say solution.... unbeliavable) suitable for my purpose. 

Here the code for benefit of other.

I have to say the true, coding .net with Autocad is not for dummy and some of the code here is not clear to me at all (but works...)

In any case I leave the original code from @norman.yuan in which I edited and replaced with other fonts (ie: web, samples from official reference... suggestion by @ActivistInvestor, and my guess...) and adding some comment (hope they make sense).

 

The code doesn't replace ATTRIBUTES (the new block has to have own ATTRIBUTES in it, as suggested by @ActivistInvestor as faster way)

The code can transfer some attribute.text from the old block to th new one.

 

 

The last question:

Could someone explain to me how come the editor doesn't refresh the screen after each foreach operation?

 

 star processing new file:

ed.WriteMessage("\nProcessing: " + Path.GetFileName(dwgfile));

...............

..............

end processing the file

ed.UpdateScreen();

but I see my screen updated just at the end of whole program... strangely enogh.

 

 

 

 

 

        [CommandMethod("REPBLK")]
        public static void RunDocCommand()
        {

            string pathDwgFiles = @"MAYPATH";
            string newBlockFile = @"DWGFILEWITHNEWBLOCK";
            string oldBlkName = "OLDBLOCKNAME";
            string newBlkName = "NEWBLOCKNAME";

            var workingDb = HostApplicationServices.WorkingDatabase;

            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;


            try
            {
                ed.WriteMessage("\nSTART BLOCK REPLACE PROCESS\n");

                string[] dwgFiles = Directory.GetFiles(pathDwgFiles, "*.dwg", SearchOption.AllDirectories);
                foreach (var dwgfile in dwgFiles)
                {
                    // Open target drawing as side database.
                    // It makes the processing a lot faster than opening
                    // drawing in Editor visibly.
                    // One can choose open the drawing in Editor, if desired.
                    ed.WriteMessage("\nProcessing: " + Path.GetFileName(dwgfile));
                    using (var db = OpenSideDatabase(dwgfile))
                    {
                        HostApplicationServices.WorkingDatabase = db;
                        if (!ReplaceBlocks(db, oldBlkName, newBlkName, newBlockFile))
                            ed.WriteMessage("\nOld Block NOT foud in: " + Path.GetFileName(dwgfile));
                        else
                            RemoveBlockFromDb(db, oldBlkName); //remove oldBlock

                        db.RetainOriginalThumbnailBitmap = true;
                        db.SaveAs(dwgfile, true, DwgVersion.Current, null);
                    }
                    ed.UpdateScreen();
                }
            }
            catch (System.Exception ex)
            {
                CadApp.ShowAlertDialog("Error:\r\n" + ex.Message);
            }
            finally
            {
                ed.WriteMessage("\nEND BLOCK REPLACE PROCESS\n");
                HostApplicationServices.WorkingDatabase = workingDb;
                Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt();

            }
        }

        /// <summary>
        /// Open the DWG as Database
        /// </summary>
        /// <param name="dwgFileName">the dwg file name full path</param>
        /// <returns>the Database</returns>
        private static Database OpenSideDatabase(string dwgFileName)
        {
            var db = new Database(false, true);
            db.ReadDwgFile(dwgFileName, FileOpenMode.OpenForReadAndWriteNoShare, false, null);
            return db;
        }

        private static bool ReplaceBlocks(Database db, string oldBlkName, string newBlkName, string newBlockFile)
        {
            // Find all "OldBlock" references and collect their attribute data
            // If only blockreference on certain layout is targeted, this is where
            // one can decide which layout to be excluded
            var dwgAttData = CollectOldBlockAttributeData(db, oldBlkName);
            if (dwgAttData.Count == 0)
            {
                //CadApp.ShowAlertDialog("No \"" + oldBlkName + "\" found!");
                return false;
            }

            // Make sure "NewBlock" is defined in the drawing. If not, get it from 
            // a block drawing file (Database.Insert(); or the the block definition
            // is in a drawing where many blocks are defined, use 
            // use Database.WblockCloneObjects() to bring this block definition
            // into this drawing
            var newBlkDefId = EnsureNewBlockDefinition(db, newBlkName, newBlockFile);
            if (newBlkDefId.IsNull)
            {
                CadApp.ShowAlertDialog("NewBlock definition is not found in source drawing!");
                return false;
            }

            // Replacing "OldBlock" references by
            // 1. Insert "NewBlock" at the same position/same layer
            // 2. Sych  attribute values (because both old and new blocks have the same Attrs.
            // 3. Erase "OldBlock" reference

            ReplaceOldBlocks(db, newBlkDefId, dwgAttData, newBlkName);

            return true;
        }



        #region find all "OldBlock" and their attribute information
        private static DrawingAttributeData CollectOldBlockAttributeData(Database db, string oldBlkName)
        {
            var attData = new DrawingAttributeData();
            using (var tran = db.TransactionManager.StartTransaction())
            {
                var dic = (DBDictionary)tran.GetObject(db.LayoutDictionaryId, OpenMode.ForRead);
                foreach (DBDictionaryEntry entry in dic)
                {
                    var layout = (Layout)tran.GetObject(entry.Value, OpenMode.ForRead);
                    var layoutAttData = CollectOldBlockAttributeDataOnLayout(oldBlkName, layout.BlockTableRecordId, tran);
                    if (layoutAttData.Count > 0)
                    {
                        attData.Add(layout.BlockTableRecordId, layoutAttData);
                    }
                }
                tran.Commit();
            }
            return attData;
        }

        private static List<BlockAttributeData> CollectOldBlockAttributeDataOnLayout(
                                                string oldBlkName, ObjectId layoutBlockId, Transaction tran)
        {
            var layoutAttData = new List<BlockAttributeData>();
            var layoutBlock = (BlockTableRecord)tran.GetObject(layoutBlockId, OpenMode.ForRead);
            foreach (ObjectId id in layoutBlock)
            {
                if (id.ObjectClass.DxfName.ToUpper() == "INSERT")
                {
                    var blk = (BlockReference)tran.GetObject(id, OpenMode.ForRead);
                    if (blk.Name.ToUpper().Contains(oldBlkName.ToUpper())) //I use contain for similar names in my list
                    {
                        var blkAttData = CollectOldBlockAttributes(blk, tran);
                        if (blkAttData.Attributes.Count > 0)
                        {
                            layoutAttData.Add(blkAttData);
                        }
                    }
                }
            }
            return layoutAttData;
        }

        private static BlockAttributeData CollectOldBlockAttributes(BlockReference bref, Transaction tran)
        {
            //bref.Name is the layout name.

            var blkAttData = new BlockAttributeData();
            blkAttData.BlkRefId = bref.ObjectId;
            blkAttData.Layer = bref.Layer;

            foreach (ObjectId id in bref.AttributeCollection)
            {
                var att = (AttributeReference)tran.GetObject(id, OpenMode.ForRead);
                if (att.IsConstant)
                    continue;

                if (!blkAttData.Attributes.ContainsKey(att.Tag.ToUpper()))
                {
                    blkAttData.Attributes.Add(att.Tag.ToUpper(), att.TextString);
                }
            }
            return blkAttData;
        }

        #endregion

        #region make sure "NewBlock" definition exists

        private static ObjectId EnsureNewBlockDefinition(Database db, string newBlkName, string newBlockFile)
        {
            var blkId = ObjectId.Null;

            using (var tran = db.TransactionManager.StartTransaction())
            {
                var bt = (BlockTable)tran.GetObject(db.BlockTableId, OpenMode.ForRead);
                if (bt.Has(newBlkName))
                    blkId = bt[newBlkName]; //verify if the current drawing has the new block
                tran.Commit();
            }

            if (blkId.IsNull) //if the block isn't in, get it
            {
                blkId = InsertNewBlockDefinition(db, newBlkName, newBlockFile);
            }
            return blkId;
        }

        /// <summary>
        /// Clones in db the block from the file
        /// </summary>
        /// <param name="db">destination database</param>
        /// <param name="blkName">block name</param>
        /// <param name="blkFile">block's source file full path</param>
        /// <returns>the block's objId</returns>
        private static ObjectId InsertNewBlockDefinition(Database db, string blkName, string blkFile)
        {
            var blkId = ObjectId.Null;
            using (var blkDb = new Database(false, true))
            {
                blkDb.ReadDwgFile(blkFile, FileOpenMode.OpenForReadAndReadShare, false, null);

                //this Works:
                //need to crate collectionObject for wblockClone method:
                ObjectIdCollection objColl = new ObjectIdCollection();
                
                objColl.Add(GetBlkId(blkDb, blkName));
                IdMapping map = new IdMapping();
                
                //cloneObject
                blkDb.WblockCloneObjects(objColl, db.BlockTableId, map, DuplicateRecordCloning.Replace, false);
                blkId = GetBlkId(db, blkName); //keep the id of cloned block

                //if I use deepclone, as is doesn't work
                //blkDb.DeepCloneObjects(objColl, db.BlockTableId, map, false);
                
                //if I use Insert, as is doesn't work:
                //blkId = db.Insert(blkName, blkDb, false);
            }
            return blkId;
        }


        #endregion

        #region do the replacing work

        private static void ReplaceOldBlocks(Database db, ObjectId newBlkDefId,
                                             DrawingAttributeData dwgAttData, string newBlkName)
        {
            using (var tran = db.TransactionManager.StartTransaction())
            {
                foreach (var item in dwgAttData)
                {
                    //item.key is an objectId
                    var layoutBlock = (BlockTableRecord)tran.GetObject(item.Key, OpenMode.ForWrite);
                    var newBlock = (BlockTableRecord)tran.GetObject(newBlkDefId, OpenMode.ForRead);

                    //foreach layout
                    foreach (var blkData in item.Value)
                    {
                        //get the position
                        var oldBlk = (BlockReference)tran.GetObject(blkData.BlkRefId, OpenMode.ForRead);
                        var position = oldBlk.Position; 


                        CreateNewBlockReference(db, layoutBlock, newBlock, position, blkData.Layer,
                                                blkData.Attributes, tran);

                        //erase block doesn't work - i will erase later see: RemoveBlockFromDb
                        //oldBlk.UpgradeOpen();
                        //oldBlk.Erase();
                        //oldBlk.Dispose();
                    }
                }
                tran.Commit();
            }
        }

        private static void CreateNewBlockReference(Database db, BlockTableRecord layoutBlock,
                                                    BlockTableRecord newBlock, Point3d position,
                                                    string layer, Dictionary<string, string> attData,
                                                    Transaction tran)
        {
            var bref = new BlockReference(position, newBlock.ObjectId);

            bref.SetDatabaseDefaults(db);
            bref.Layer = layer;
            
            var brefId = layoutBlock.AppendEntity(bref);
            tran.AddNewlyCreatedDBObject(bref, true);
  
            SetAttributes(brefId, newBlock, attData, tran);
        }


        private static void SetAttributes(ObjectId brefId, BlockTableRecord newBlock,
                                          Dictionary<string, string> attData, Transaction tran)
        {
            var bref = (BlockReference)tran.GetObject(brefId, OpenMode.ForWrite);
            
            foreach (ObjectId id in newBlock)
            {
                //FROM .NET SAMPLE GUIDE
                DBObject dbObj = (DBObject)tran.GetObject(id, OpenMode.ForRead);
                if (dbObj is AttributeDefinition)
                {
                    AttributeDefinition attDef = dbObj as AttributeDefinition;
                    if (!attDef.Constant)
                    {
                        using (AttributeReference attRef = new AttributeReference())
                        {
                            attRef.SetAttributeFromBlock(attDef, bref.BlockTransform);
                            if (attDef.Tag.Contains("THE TAG I WANT TO REPLACE"))
                            {
                                //replace value gets from the old block
                                attRef.TextString = attData["THE TAG I WANT TO REPLACE"];
                            }
                            else
                            {
                                //Do nothing and leave value of new block
                            }
                            bref.AttributeCollection.AppendAttribute(attRef);
                            tran.AddNewlyCreatedDBObject(attRef, true);
                        }
                    }
                }

                //OLD VERSION 
                //var attDef = tran.GetObject(id, OpenMode.ForRead) as AttributeDefinition;
                //if (attDef != null)
                //{
                //    var att = new AttributeReference();
                //    att.SetAttributeFromBlock(attDef, bref.BlockTransform);
 
                //    if (!attDef.Constant && attData.ContainsKey("OGGETTO"))
                //    {
                //        if (attData.ContainsKey(att.Tag.ToUpper()))
                //            att.TextString = attData[att.Tag.ToUpper()];
                //    }
                //    bref.AttributeCollection.AppendAttribute(att);
                //    tran.AddNewlyCreatedDBObject(att, true);
                //}
            }
        }

        #endregion

        #region MyAdd
        /// <summary>
        /// Gets the block's ObjID from the database
        /// </summary>
        /// <param name="db">the Database</param>
        /// <param name="blkName">the block name</param>
        /// <returns>the objID</returns>
        public static ObjectId GetBlkId(Database db, string blkName)
        {
            ObjectId blkId = ObjectId.Null;

            if (db == null)
                return ObjectId.Null;

            if (string.IsNullOrWhiteSpace(blkName))
                return ObjectId.Null;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTable bt = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
                if (bt.Has(blkName))
                    blkId = bt[blkName];
                else //looking for similar name...
                {
                    foreach (ObjectId item in bt)
                    {
                        BlockTableRecord btr = (BlockTableRecord)tr.GetObject(item, OpenMode.ForRead);
                        if (btr.Name.ToUpper().Contains(blkName.ToUpper()))
                        {
                            blkId = item;
                            break;
                        }
                    }
                }
                tr.Commit();
            }
            return blkId;
        }

        /// <summary>
        /// Get the Value of Attribute from block
        /// </summary>
        /// <param name="btrId">The object database</param>
        /// <param name="blockName">the block name</param>
        /// <param name="attbName"> the attribute name</param>
        /// <returns>the attribute value</returns>
        private static string GetAttribValueFromBlock(ObjectId btrId, string blockName, string attbName)
        {
            Database db = btrId.Database;
            string txtValue = string.Empty;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForRead);

                // Test each entity in the container...
                foreach (ObjectId entId in btr)
                {
                    Entity ent = tr.GetObject(entId, OpenMode.ForRead) as Entity;
                    if (ent != null)
                    {
                        BlockReference br = ent as BlockReference;
                        if (br != null)
                        {
                            BlockTableRecord bd = (BlockTableRecord)tr.GetObject(br.BlockTableRecord, OpenMode.ForRead);

                            // ... to see whether it's a block with
                            // the name we're after
                            if (bd.Name.ToUpper() == blockName)
                            {

                                // Check each of the attributes...
                                foreach (ObjectId arId in br.AttributeCollection)
                                {
                                    DBObject obj = tr.GetObject(arId, OpenMode.ForRead);
                                    AttributeReference ar = obj as AttributeReference;
                                    if (ar != null)
                                    {
                                        // ... to see whether it has
                                        // the tag we're 
                                        if (ar.Tag.ToUpper() == attbName)
                                            txtValue = ar.TextString;
                                    }
                                }
                            }

                            // Recurse for nested blocks
                            //doesn't needed for my block
                            //changedCount += UpdateAttributesInBlock(br.BlockTableRecord,blockName,attbName,attbValue);
                        }
                    }
                }
                tr.Commit();
            }
            return txtValue;
        }

        private static bool SetAttributeInBlock(ObjectId btrId, string blockName, string attbName, string attbValue)
        {
            Database db = btrId.Database;
            bool gotcha = false;
            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTableRecord btr = (BlockTableRecord)tr.GetObject(btrId, OpenMode.ForRead);

                // Test each entity in the container...
                foreach (ObjectId entId in btr)
                {
                    Entity ent = tr.GetObject(entId, OpenMode.ForRead) as Entity;
                    if (ent != null)
                    {
                        BlockReference br = ent as BlockReference;
                        if (br != null)
                        {
                            BlockTableRecord bd = (BlockTableRecord)tr.GetObject(br.BlockTableRecord, OpenMode.ForRead);

                            // ... to see whether it's a block with
                            // the name we're after
                            if (bd.Name.ToUpper() == blockName)
                            {

                                // Check each of the attributes...
                                foreach (ObjectId arId in br.AttributeCollection)
                                {
                                    DBObject obj = tr.GetObject(arId, OpenMode.ForRead);
                                    AttributeReference ar = obj as AttributeReference;
                                    if (ar != null)
                                    {
                                        // ... to see whether it has
                                        // the tag we're 
                                        if (ar.Tag.ToUpper() == attbName)
                                        {
                                            // If so, update the value
                                            // and increment the counter
                                            ar.UpgradeOpen();
                                            ar.TextString = attbValue;
                                            ar.DowngradeOpen();
                                            gotcha = true;
                                        }
                                    }
                                }
                            }

                            // Recurse for nested blocks
                            //doesn't needed for my block
                            //changedCount += UpdateAttributesInBlock(br.BlockTableRecord,blockName,attbName,attbValue);
                        }
                    }
                }
                tr.Commit();
            }
            return gotcha;
        }


        public static void RemoveBlockFromDb(Database db, string blkName)
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;


            ObjectId blkId = GetBlkId(db, blkName);
            if (!EraseBlkRefs(blkId))
                ed.WriteMessage(string.Format("\n failed to erase blockreferences for: {0}", blkId.ToString()));

            if (!EraseBlk(blkId))
                ed.WriteMessage(string.Format("\n Failed to Erase Block: {0}", blkId.ToString()));
            else
                ed.WriteMessage("\nErased" + blkId.ToString()); 

        }
        public static bool EraseBlkRefs(ObjectId blkId)
        {
            bool blkRefsErased = false;

            if (blkId.IsNull)
                return false;

            Database db = blkId.Database;
            if (db == null)
                return false;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {
                BlockTableRecord blk = (BlockTableRecord)tr.GetObject(blkId, OpenMode.ForRead);
                var blkRefs = blk.GetBlockReferenceIds(true, true);
                if (blkRefs != null && blkRefs.Count > 0)
                {
                    foreach (ObjectId blkRefId in blkRefs)
                    {
                        BlockReference blkRef = (BlockReference)tr.GetObject(blkRefId, OpenMode.ForWrite);
                        blkRef.Erase();
                    }
                    blkRefsErased = true;
                }
                tr.Commit();
            }
            return blkRefsErased;
        }
        public static bool EraseBlk(ObjectId blkId)
        {
            bool blkIsErased = false;

            if (blkId.IsNull)
                return false;

            Database db = blkId.Database;
            if (db == null)
                return false;

            using (Transaction tr = db.TransactionManager.StartTransaction())
            {

                BlockTableRecord blk = (BlockTableRecord)tr.GetObject(blkId, OpenMode.ForRead);
                var blkRefs = blk.GetBlockReferenceIds(true, true);
                if (blkRefs == null || blkRefs.Count == 0)
                {
                    blk.UpgradeOpen();
                    blk.Erase();
                    blkIsErased = true;
                }
                tr.Commit();
            }
            return blkIsErased;
        }
        #endregion
0 Likes
Message 18 of 19

ActivistInvestor
Mentor
Mentor

 See the line I added to your code below (highlighted in red):


@micle.space wrote:

 

The last question:

Could someone explain to me how come the editor doesn't refresh the screen after each foreach operation?

 

 star processing new file:

ed.WriteMessage("\nProcessing: " + Path.GetFileName(dwgfile));

...............

..............

end processing the file

ed.UpdateScreen();

but I see my screen updated just at the end of whole program... strangely enogh.

 

 

 

 

                string[] dwgFiles = Directory.GetFiles(pathDwgFiles, "*.dwg", SearchOption.AllDirectories);
                foreach (var dwgfile in dwgFiles)
                {
                    // Open target drawing as side database.
                    // It makes the processing a lot faster than opening
                    // drawing in Editor visibly.
                    // One can choose open the drawing in Editor, if desired.
                    ed.WriteMessage("\nProcessing: " + Path.GetFileName(dwgfile));
System.Windows.Forms.Application.DoEvents(); using (var db = OpenSideDatabase(dwgfile)) { HostApplicationServices.WorkingDatabase = db; if (!ReplaceBlocks(db, oldBlkName, newBlkName, newBlockFile)) ed.WriteMessage("\nOld Block NOT foud in: " + Path.GetFileName(dwgfile)); else RemoveBlockFromDb(db, oldBlkName); //remove oldBlock db.RetainOriginalThumbnailBitmap = true; db.SaveAs(dwgfile, true, DwgVersion.Current, null); } ed.UpdateScreen(); } } catch (System.Exception ex) { CadApp.ShowAlertDialog("Error:\r\n" + ex.Message); } finally { ed.WriteMessage("\nEND BLOCK REPLACE PROCESS\n"); HostApplicationServices.WorkingDatabase = workingDb; Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt(); } }
Message 19 of 19

micle.space
Enthusiast
Enthusiast

doh.png

0 Likes