I'm working on a block replacement code. It will update blocks in any drawing ( opened/unopened, current/non-current ). It works well with unopened drawings right now. It works with opened drawings, but not as well as I would like to release it. The issue seems to be with attributes. It will not update them correctly all the time, and I don't know why.
RedefiningBlock = a custom class that holds information about the redefining of the block.
Here is the main portion of the code that does the updating.
void ProceedButton ( object sender, EventArgs e )
{
DocumentCollection DocCol = AcadApp.DocumentManager;
Database cDb = DocCol.MdiActiveDocument.Database;
Editor Ed = DocCol.MdiActiveDocument.Editor;
foreach ( KeyValuePair<string, List<RedefiningBlock>> kvp in FinalMappingDict ) {
Database reDb;
Document reOpenDoc = null;
DocumentLock reDocLock = null;
if ( kvp.Value.Count == 0 ) continue;
reOpenDoc = MyUtility.GetDocumentFrom( DocCol, kvp.Key );
if ( reOpenDoc == null ) {
reDb = new Database( false, true );
reDb.ReadDwgFile( kvp.Key, FileShare.ReadWrite, true, null );
HostApplicationServices.WorkingDatabase = reDb;
}
else {
reDocLock = reOpenDoc.LockDocument();
reDb = reOpenDoc.Database;
}
using ( Transaction reTrans = reDb.TransactionManager.StartTransaction() ) {
foreach ( RedefiningBlock rb in kvp.Value ) {
Database deDb;
Document deOpenDoc = null;
DocumentLock deDocLock = null;
ObjectId reObjId = MyUtility.GetNonErasedTableRecordId( reDb.BlockTableId, rb.Name );
if ( reObjId.IsNull ) continue;
BlockTableRecord reBlkTblRec = reTrans.GetObject( reObjId, OpenMode.ForWrite ) as BlockTableRecord;
foreach ( ObjectId id in reBlkTblRec ) {
reTrans.GetObject( id, OpenMode.ForWrite ).Erase();
}
deOpenDoc = MyUtility.GetDocumentFrom( DocCol, rb.RedefiningDrawingPath );
if ( deOpenDoc == null ) {
deDb = new Database( false, true );
deDb.ReadDwgFile( rb.RedefiningDrawingPath, FileShare.ReadWrite, true, null );
}
else {
deDocLock = deOpenDoc.LockDocument();
deDb = deOpenDoc.Database;
}
ObjectId deObjId = MyUtility.GetNonErasedTableRecordId( deDb.BlockTableId, rb.RedefiningName );
if ( deObjId == null ) continue;
using ( Transaction deTrans = deDb.TransactionManager.StartTransaction() ) {
ObjectIdCollection ObjIdCol = new ObjectIdCollection();
BlockTableRecord deBlkTblRec = deTrans.GetObject( deObjId, OpenMode.ForRead ) as BlockTableRecord;
foreach ( ObjectId id in deBlkTblRec ) {
ObjIdCol.Add( id );
}
deDb.WblockCloneObjects( ObjIdCol, reBlkTblRec.ObjectId, new IdMapping(), DuplicateRecordCloning.Ignore, true );
}
MapAttributes( reBlkTblRec.ObjectId, rb.AttributeMapping );
if ( deOpenDoc == null )
deDb.Dispose();
else
deDocLock.Dispose();
}
reTrans.Commit();
}
if ( HostApplicationServices.WorkingDatabase != cDb )
HostApplicationServices.WorkingDatabase = cDb;
if ( reOpenDoc == null ) {
reDb.RetainOriginalThumbnailBitmap = true;
reDb.SaveAs( kvp.Key, DwgVersion.Current );
Ed.WriteMessage( "{0} Saved file: {1}", System.Environment.NewLine, reDb.Filename );
reDb.Dispose();
}
else
reDocLock.Dispose();
}
this.Close();
}
Here is the portion that updates the attributes.
void MapAttributes ( ObjectId id, Dictionary<string, string> mappingDict )
{
using ( Transaction Trans = id.Database.TransactionManager.StartTransaction() ) {
BlockTableRecord BlkTblRec = Trans.GetObject( id, OpenMode.ForRead ) as BlockTableRecord;
foreach ( ObjectId objId in BlkTblRec.GetBlockReferenceIds( true, true ) ) {
if ( objId.IsErased ) continue;
Dictionary<string, string> Dict = new Dictionary<string, string>();
BlockReference BlkRef = Trans.GetObject( objId, OpenMode.ForWrite ) as BlockReference;
foreach ( ObjectId attId in BlkRef.AttributeCollection as AttributeCollection ) {
if ( attId.IsErased ) continue;
AttributeReference AttRef = Trans.GetObject( attId, OpenMode.ForWrite ) as AttributeReference;
if ( mappingDict.ContainsKey( AttRef.Tag ) )
Dict.Add( mappingDict[ AttRef.Tag ], AttRef.TextString );
AttRef.Erase();
}
if ( BlkTblRec.HasAttributeDefinitions ) {
foreach ( ObjectId attId in BlkTblRec ) {
if ( attId.IsErased ) continue;
AttributeDefinition AttDef = Trans.GetObject( attId, OpenMode.ForRead ) as AttributeDefinition;
if ( AttDef != null ) {
AttributeReference AttRef = new AttributeReference();
AttRef.SetAttributeFromBlock( AttDef, BlkRef.BlockTransform );
BlkRef.AttributeCollection.AppendAttribute( AttRef );
Trans.AddNewlyCreatedDBObject( AttRef, true );
if ( Dict.ContainsKey( AttRef.Tag ) )
AttRef.TextString = Dict[ AttRef.Tag ];
}
}
}
}
Trans.Commit();
}
}
Acad = 2009
.Net = 2.0
If anything is needed let me know. Thanks in advance.