Thanks for Chris, Dan and Dale for pointing out the obvious issue(s) with my last post. Let’s just blame it on a few holiday cobwebs needing brushing away during the first week back in the saddle. :-)
The main issue with my previous implementation was that I’d somehow forgotten that Database.Insert() allows you to insert into a named block definition. This simple function does all my previous, manual approach did and more.
The secondary issue – but still very important to those using annotation scaling – is that the previous code does not work for annotative blocks, as Dan very rightly pointed out. I’ve incorporated Dan’s approach into today’s post to make it more complete.
I’ve decided to leave the original post as it is – as the technique is somewhat interesting at a certain level – even if today’s post supercedes it.
Here’s the updated C# code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using System.IO;
using System;
namespace BlockImport
{
public class BlockImportClass
{
[CommandMethod("CBL")]
public void CombineBlocksIntoLibrary()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database destDb = doc.Database;
// Get name of folder from which to load and import blocks
PromptResult pr =
ed.GetString("\nEnter the folder of source drawings: ");
if (pr.Status != PromptStatus.OK)
return;
string pathName = pr.StringResult;
// Check the folder exists
if (!Directory.Exists(pathName))
{
ed.WriteMessage(
"\nDirectory does not exist: {0}", pathName
);
return;
}
// Get the names of our DWG files in that folder
string[] fileNames = Directory.GetFiles(pathName, "*.dwg");
// A counter for the files we've imported
int imported = 0, failed = 0;
// For each file in our list
foreach (string fileName in fileNames)
{
// Double-check we have a DWG file (probably unnecessary)
if (fileName.EndsWith(
".dwg",
StringComparison.InvariantCultureIgnoreCase
)
)
{
// Catch exceptions at the file level to allow skipping
try
{
// Suggestion from Thorsten Meinecke...
string destName =
SymbolUtilityServices.GetSymbolNameFromPathName(
fileName, "dwg"
);
// And from Dan Glassman...
destName =
SymbolUtilityServices.RepairSymbolName(
destName, false
);
// Create a source database to load the DWG into
using (Database db = new Database(false, true))
{
// Read the DWG into our side database
db.ReadDwgFile(fileName, FileShare.Read, true, "");
bool isAnno = db.AnnotativeDwg;
// Insert it into the destination database as
// a named block definition
ObjectId btrId = destDb.Insert(
destName,
db,
false
);
if (isAnno)
{
// If an annotative block, open the resultant BTR
// and set its annotative definition status
Transaction tr =
destDb.TransactionManager.StartTransaction();
using (tr)
{
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(
btrId,
OpenMode.ForWrite
);
btr.Annotative = AnnotativeStates.True;
tr.Commit();
}
}
// Print message and increment imported block counter
ed.WriteMessage("\nImported from \"{0}\".", fileName);
imported++;
}
}
catch (System.Exception ex)
{
ed.WriteMessage(
"\nProblem importing \"{0}\": {1} - file skipped.",
fileName, ex.Message
);
failed++;
}
}
}
ed.WriteMessage(
"\nImported block definitions from {0} files{1} in " +
"\"{2}\" into the current drawing.",
imported,
failed > 0 ? " (" + failed + " failed)" : "",
pathName
);
}
}
}
The results are just as we saw with the previous code, so I won’t repeat them.
Update
I made a small update to the code, to make use of SymbolUtilityServices.GetSymbolNameFromPathName() rather than Path.GetFileNameWithoutExtension(). Thanks to Thorsten Meinecke for making this suggestion.
Update 2
Followed by a minor code update to fix simplify the post-edit of annotative block definitions as well as an additional call to SymbolUtilityServices.RepairSymbolName() recommended by Dan Glassman (thanks, Dan! :-).