Mark, I think, posted a snippet under
http://www.theswamp.org/index.php?topic=31859.msg422435#msg422435 in which the dynamic block references are enumerated by GetBlockReferenceIds(). Which is often not what one would want, e.g. in case of nested and/or unreferenced blocks.
My suggestion uses a custom selection filter (which is one possible way to iterate the model space) and relies on the fact that the anonymous BlockTableRecord corresponding to a dynamic BlockReference has a XData entry which contains the Handle of the unparametrized BlockTableRecord. The upshot is that I'm not comparing names, but only Handles.
Implementation in F#, will port to C# if there's time for and interest in it.
Cheers, Thorsten
let (|TypedValue|) (tv: TypedValue) = tv.TypeCode, tv.Value
let tryPickFromXData f (xData: ResultBuffer) =
if xData = null then None
else xData.AsArray() |> Array.tryPick f
type Transaction with
member tr.OpenForRead oid = tr.GetObject(oid, OpenMode.ForRead)
member tr.TryGetBTRHandleFromDynamicBlockReference oid =
let br = tr.OpenForRead oid :?> BlockReference
if br.AnonymousBlockTableRecord.IsNull then
let btr = tr.OpenForRead br.BlockTableRecord :?> BlockTableRecord
btr.Handle |> string |> Some
else
let btr = tr.OpenForRead br.AnonymousBlockTableRecord :?> BlockTableRecord
btr.GetXDataForApplication "AcDbBlockRepBTag"
|> tryPickFromXData
(fun (TypedValue(k, v)) ->
if k = int16 DxfCode.ExtendedDataHandle then string v |> Some
else None
)
type Editor with
member ed.TrySelectAnonymousBlocks btrHand =
use tr = ed.Document.Database.TransactionManager.StartTransaction()
let selectionFilter =
Seq.cast<SelectedObject>
>> Seq.mapi
(fun i so ->
i, tr.TryGetBTRHandleFromDynamicBlockReference so.ObjectId
)
>> Seq.choose
(function
| _, Some hand when hand = btrHand -> None
| i, _ -> Some i
)
use selectionAdded =
ed.SelectionAdded
|> Observable.subscribe
(fun e ->
e.AddedObjects
|> selectionFilter
|> Seq.iter e.Remove
)
let sf =
new SelectionFilter[|
new TypedValue(int DxfCode.Start, "INSERT") |]
let pso =
new PromptSelectionOptions(
MessageForAdding = "\nSelect block references: " )
let psr = ed.GetSelection(pso, sf)
let psr =
if psr.Status = PromptStatus.Error then ed.SelectAll sf
else psr
tr.Commit()
if psr.Status = PromptStatus.OK && psr.Value.Count > 0 then
Some psr.Value
else None
[<CommandMethod "DynBlkSel">]
let dynBlkSel() =
let ed = acApp.DocumentManager.MdiActiveDocument.Editor
let db = acApp.DocumentManager.MdiActiveDocument.Database
use tr = db.TransactionManager.StartTransaction()
let peo =
new PromptEntityOptions(
"\nSelect Blockreference: ", AllowNone = true )
peo.SetRejectMessage("\nNo Blockreference. ")
peo.AddAllowedClass(typeof<BlockReference>, false)
let per = ed.GetEntity peo
if per.Status = PromptStatus.OK then Some per.ObjectId
else None
|> Option.bind tr.TryGetBTRHandleFromDynamicBlockReference
|> function
| None ->
ed.WriteMessage("\nCan't find named block. ")
| Some btrHand ->
ed.WriteMessage("\nBlock selected with Handle {0}. ", btrHand)
ed.TrySelectAnonymousBlocks btrHand
|> function
| None -> ed.WriteMessage("\nNothing selected. ")
| Some sset ->
ed.WriteMessage("\n{0} blocks selected. ", sset.Count)
tr.Commit()