- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
I am trying to create a command named "SYNCBLOCKS" that allows the user to select a block reference and then choose drawings they want to redefine the referenced block in.
I tried to use the method shown in this blog post: https://adndevblog.typepad.com/autocad/2012/05/redefining-a-block.html
My Testing Setup: I have a drawing that I open in AutoCAD with a block named "VSE-LAYERS" and a reference to that block in model space. In AutoCAD I run the custom command "SYNCBLOCKS" and select the block reference, and then in the file prompt I select a different file that also has a block named "VSE-LAYERS".
Desired Result: The block in the selected file to match the block in the original file.
Actual Result: AutoCAD throws a self reference error
Command: SYNCBLOCKS
Syncing blockSelect block to sync:
Selected "VSE-LAYERS"Loading AEC Base...
Loading AEC Base Extended...
Loading AEC Core...
Loading AEC Project Base...
Loading AEC Architectural Base...
Loading AEC Schedule...
Block VSE-LAYERS references itself
Error syncing block in "C:\Users\nate.diven\Desktop\VZW NODE 03.dwg": Autodesk.AutoCAD.Runtime.Exception: eSelfReference
at Autodesk.AutoCAD.DatabaseServices.Database.Insert(String blockName, Database dataBase, Boolean preserveSourceDatabase)
at VectorCadCommands.OtherCommands.SyncBlocks() in C:\Users\nate.diven\Documents\GitHub\VectorCadCommands\VectorCadCommands\OtherCommands.cs:line 619
So far this is what I have:
[CommandMethod("SyncBlocks")]
public void SyncBlocks()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
ed.WriteMessage("\nSyncing block");
ObjectId pickedId = ObjectId.Null;
PromptEntityOptions opt = new PromptEntityOptions("Select block to sync");
opt.AllowNone = false;
// prompt user to select block reference
PromptEntityResult res = ed.GetEntity(opt);
if (res.Status != PromptStatus.OK)
{
ed.WriteMessage("\ninvalid selection");
}
pickedId = res.ObjectId;
string blockName = ""; // will store selected block name
// string filePath = db.Filename; // this was used for another method I was trying
using (var tx = db.TransactionManager.StartTransaction())
{
BlockReference br = tx.GetObject(pickedId, OpenMode.ForRead) as BlockReference;
if (br == null)
{
ed.WriteMessage("\ninvalid selection");
return;
}
blockName = br.Name;
tx.Dispose();
}
ed.WriteMessage($"\nSelected \"{blockName}\"");
OpenFileDialog ofd = new OpenFileDialog("Select DWGs to sync", null, "dwg", "DWG Files (*.dwg)|*.dwg", OpenFileDialog.OpenFileDialogFlags.AllowMultiple);
// prompt user to select drawing files
var dr = ofd.ShowDialog();
if (dr != System.Windows.Forms.DialogResult.OK)
{
ed.WriteMessage("\nNo files selected");
return;
}
var dm = Application.DocumentManager;
// loop through each selected file
foreach (var file in ofd.GetFilenames())
{
try
{
using(var tempDb = new Database(false, true))
{
// this is the database the block needs to be updated in
tempDb.ReadDwgFile(file, FileOpenMode.OpenForReadAndWriteNoShare, true, null);
using (var tx = tempDb.TransactionManager.StartTransaction())
{
var bt = tx.GetObject(tempDb.BlockTableId, OpenMode.ForRead, false, true);
var btrId = tempDb.Insert(blockName, db, true);
if (btrId != ObjectId.Null)
{
var btr = tx.GetObject(btrId, OpenMode.ForRead) as BlockTableRecord;
var brefIds = btr.GetBlockReferenceIds(false, true);
foreach (ObjectId id in brefIds)
{
var bref = tx.GetObject(id, OpenMode.ForWrite) as BlockReference;
bref.RecordGraphicsModified(true);
}
}
tx.Commit();
}
tempDb.SaveAs(file, DwgVersion.AC1027);
}
}
catch (System.Exception ex)
{
dm.MdiActiveDocument.Editor.WriteMessage($"\nError syncing block in \"{file}\": {ex}");
}
}
}
Solved! Go to Solution.