I'm implementing a macro with the purpose to export the names of all blocks in a drawing, wether they're present in the model space or not.
The issue I'm encountring is when I try to include the visibilities of the dynamic blocks in the export.
So I would appreciate if anyone could help show me how to collect the information about the visibilities of a dynamic block. Thank you in advance.
[CommandMethod("ExportBlocksListToCsv")]
public void ExportBlocksListToCsv()
{
Document doc = Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
// Get the path of the open drawing file
string drawingPath = db.Filename;
string csvFilePath = drawingPath.Replace(".dwg", " Blocks.csv");
List<string> blockNames = new List<string>();
using (Transaction tr = db.TransactionManager.StartTransaction())
{
// Open the block table
BlockTable blockTable = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
if (blockTable != null)
{
// Iterate through each block table record (block definition)
foreach (ObjectId btrId in blockTable)
{
BlockTableRecord btr = tr.GetObject(btrId, OpenMode.ForRead) as BlockTableRecord;
if (btr == null || btr.IsLayout || btr.IsAnonymous)
{
continue;
}
blockNames.Add(btr.Name);
if (btr.IsDynamicBlock)
{
//INSERT CODE HERE WHERE YOU ADD THE VISIBILITIES OF THE DYNAMIC BLOCK TO THE LIST blockNames.
}
}
}
tr.Commit();
}
_exportListToCsv(blockNames, csvFilePath);
}
Solved! Go to Solution.
Solved by _gile. Go to Solution.
I think you need to work with a BlockReference, not with a BlockTableRecord, and then iterate blockReference.DynamicBlockReferencePropertyCollection.
If you don't have any references already inserted, then you can insert one temporarily, look at the list and delete it.
Hi,
To get the dynamic properties of a block definition, you can use its DXF data.
Here's a example using some extension methods
Extension methods
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using AcRx = Autodesk.AutoCAD.Runtime;
namespace DynamicBlockPropertyExtension
{
public static class Extension
{
// Replace the DLL name according to the AutoCAD targeted version
// 2013-2014: "acdb19.dll"
// 2015-2016: "acdb20.dll"
// 2017: "acdb21.dll"
// 2018: "acdb22.dll"
// 2019-2020: "acdb23.dll"
// 2021-2024: "acdb24.dll"
// Replace the EntryPoint according to AutoCAD plateform
// 32 bits: "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AAY01JVAcDbObjectId@@@Z"
// 64 bits: "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z"
[System.Security.SuppressUnmanagedCodeSecurity]
[DllImport("acdb24.dll", CallingConvention = CallingConvention.Cdecl,
EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z")]
static extern AcRx.ErrorStatus acdbGetAdsName(out AdsName ename, ObjectId id);
[System.Security.SuppressUnmanagedCodeSecurity]
[DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl,
EntryPoint = "acdbEntGet")]
static extern IntPtr acdbEntGet(AdsName ename);
public static ResultBuffer EntGet(ObjectId id)
{
var errorStatus = acdbGetAdsName(out AdsName ename, id);
if (errorStatus != AcRx.ErrorStatus.OK)
throw new AcRx.Exception(errorStatus);
var result = acdbEntGet(ename);
if (result != IntPtr.Zero)
return ResultBuffer.Create(result, true);
return null;
}
public static IEnumerable<IEnumerable<TypedValue>> GetDynamicPropertiesDxfData(this BlockTableRecord btr, Transaction tr)
{
if (btr == null)
throw new ArgumentNullException(nameof(btr));
if (tr == null)
throw new ArgumentNullException(nameof(tr));
var xDictId = btr.ExtensionDictionary;
if (xDictId.IsNull)
throw new Exception("eNoExtensionDictionary");
var xDict = (DBDictionary)tr.GetObject(xDictId, OpenMode.ForRead);
if (!xDict.Contains("ACAD_ENHANCEDBLOCK"))
throw new Exception("eNotDynamicBlock");
var resbuf = EntGet(xDict.GetAt("ACAD_ENHANCEDBLOCK"));
if (resbuf == null)
throw new AcRx.Exception(AcRx.ErrorStatus.InvalidResultBuffer);
return resbuf.Cast<TypedValue>()
.Where(tv => tv.TypeCode == 360)
.Select(tv => EntGet((ObjectId)tv.Value).Cast<TypedValue>());
}
public static T GetValue<T>(this IEnumerable<TypedValue> typedValues, short typeCode) =>
(T)typedValues.First(tv => tv.TypeCode == typeCode).Value;
public static IEnumerable<T> GetValues<T>(this IEnumerable<TypedValue> typedValues, short typeCode) =>
typedValues.Where(tv => tv.TypeCode == typeCode).Select(tv => (T)tv.Value);
}
}
Command example:
[CommandMethod("ListBlocks")]
public void ListBlocks()
{
var doc = Application.DocumentManager.MdiActiveDocument;
var db = doc.Database;
var ed = doc.Editor;
using (var tr = db.TransactionManager.StartTransaction())
{
var blockTable = (BlockTable)tr.GetObject(db.BlockTableId, OpenMode.ForRead);
foreach (ObjectId id in blockTable)
{
var btr = (BlockTableRecord)tr.GetObject(id, OpenMode.ForRead);
if (btr.IsLayout ||
btr.IsAnonymous ||
btr.IsDependent ||
btr.IsFromExternalReference ||
btr.IsFromOverlayReference)
continue;
ed.WriteMessage($"\nBlock name: {btr.Name}");
if (btr.IsDynamicBlock)
{
var visibParam = btr.GetDynamicPropertiesDxfData(tr)
.FirstOrDefault(tvs => tvs.GetValue<string>(0) == "BLOCKVISIBILITYPARAMETER");
if (visibParam != null)
{
ed.WriteMessage($"\n\tVisibilty parameter name: {visibParam.GetValue<string>(301)}" +
$"\n\t\tAllowed values:");
foreach (string value in visibParam.GetValues<string>(303))
{
ed.WriteMessage($"\n\t\t- {value}");
}
}
}
}
tr.Commit();
}
}
Can't find what you're looking for? Ask the community or share your knowledge.