Hi all,
I have got this code by KEAN WALMSLEY.
His code will ask user to select a block and then list all of selected block's attributes. However, I need to tweak his code a little bit and instead of user interaction, the block has to be selected by its name and through my code.
Here is his code (with slight changes to suit my purpose):
rivate Sub ListAttributes() Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor Dim db As Database = HostApplicationServices.WorkingDatabase Dim tr As Transaction = db.TransactionManager.StartTransaction() Try Dim filList As TypedValue() = New TypedValue(0) {New TypedValue(CInt(DxfCode.Start), "INSERT")} Dim filter As New SelectionFilter(filList) Dim opts As New PromptSelectionOptions() opts.MessageForAdding = "Select block references: " Dim res As PromptSelectionResult = ed.GetSelection(opts, filter) If res.Status <> PromptStatus.OK Then Return End If Dim selSet As SelectionSet = res.Value Dim idArray As ObjectId() = selSet.GetObjectIds() For Each blkId As ObjectId In idArray Dim blkRef As BlockReference = DirectCast(tr.GetObject(blkId, OpenMode.ForRead), BlockReference) Dim btr As BlockTableRecord = DirectCast(tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord) ed.WriteMessage(vbLf & "Block: " + btr.Name) btr.Dispose() Dim attCol As AttributeCollection = blkRef.AttributeCollection For Each attId As ObjectId In attCol Dim attRef As AttributeReference = DirectCast(tr.GetObject(attId, OpenMode.ForRead), AttributeReference) Dim str As String = (vbLf & attRef.Tag + " " & attRef.TextString) ed.WriteMessage(str) Next Next tr.Commit() Catch ex As Autodesk.AutoCAD.Runtime.Exception ed.WriteMessage(("Exception: " + ex.Message)) Finally tr.Dispose() End Try End Sub
Now, I need to change this Sub to a Function as below:
Private Function ListAttributes (blockName As String) As Boolean
The aim is to list all block attributes if the 'blockName' exists in drawing and return True afterwards. Oppositely it should return me False and print nothing to Editor if blockName does not exist.
Can anyone help me please?
Cheers
You have to create instead function to return your result,
pay attention to how attribute list added ByRef in the function
arguments, that's similar on OUT in C#,
thus the function will work with boolean result and also you
can get attributes if those exist
Here is a quick examole:
Public Sub ListAttributes() Dim ed As Editor = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument.Editor Dim db As Database = HostApplicationServices.WorkingDatabase Dim tr As Transaction = db.TransactionManager.StartTransaction() Try Dim filList As TypedValue() = New TypedValue(0) {New TypedValue(CInt(DxfCode.Start), "INSERT")} Dim filter As New SelectionFilter(filList) Dim opts As New PromptSelectionOptions() opts.MessageForAdding = "Select block references: " Dim res As PromptSelectionResult = ed.GetSelection(opts, filter) If res.Status <> PromptStatus.OK Then Return End If Dim selSet As SelectionSet = res.Value Dim idArray As ObjectId() = selSet.GetObjectIds() For Each blkId As ObjectId In idArray Dim blkRef As BlockReference = DirectCast(tr.GetObject(blkId, OpenMode.ForRead), BlockReference) Dim attDict As Dictionary(Of String, String) = New Dictionary(Of String, String) Dim result As Boolean = (GetAttributes(tr, blkRef, attDict)) If result = False Then ed.WriteMessage(vbLf + "{0}", result) Else For Each de As KeyValuePair(Of String, String) In attDict ed.WriteMessage(vbLf + "{0}" + vbTab + "{1}" + vbLf, de.Key, de.Value) Next ed.WriteMessage(vbLf + "{0}", result) End If Next tr.Commit() Catch ex As Autodesk.AutoCAD.Runtime.Exception ed.WriteMessage(("Exception: " + ex.Message)) Finally tr.Dispose() End Try End Sub Private Function GetAttributes(ByVal tr As Transaction, ByVal blkRef As BlockReference, ByRef attDict As Dictionary(Of String, String)) As Boolean Dim result As Boolean = True Try Dim btr As BlockTableRecord = DirectCast(tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord) If Not btr.HasAttributeDefinitions Then result = False Else Dim attCol As AttributeCollection = blkRef.AttributeCollection For Each attId As ObjectId In attCol Dim attRef As AttributeReference = DirectCast(tr.GetObject(attId, OpenMode.ForRead), AttributeReference) attDict.Add(attRef.Tag, attRef.TextString) Next End If Catch ex As Exception result = False End Try Return result End Function
Thank you my frined.
I am afraid my thread was more concerned about removing 'user interaction' part of the code. Although you clearly addressed the second part of my question, I am still confused how to GetObjectIds of my block through the code.
In other words, there is no need for user to select the block in AutoCAD. Rather, I need to pass blockname as String in my code and the code has to take care of the rest (I know it sounds less primitive than it actually is)
Additionally, thumb up to your idea of making a dictionary out of attribute tags and values. I can take advantage of that somewhere else in my code.
As I mentioned in my previous post, my ideal would be to convert ListAttribute() sub to a function and return Boolean insted of embeding the RETURN functionality inside ListAttribute subroutine. I am more willing to call ListAttributes function several times in my code. That's why I need a return value for ListAttribute() as following:
Private Function ListAttributes (blockName As String) As Boolean
I'm quite sure that you are could be able to rewrite the function from my example above
relatively to block name.
Happy coding 🙂
try removing the PromptSelectionOptions and modifying your filter list similar to this?
Dim filter As TypedValue() = {New TypedValue(0, "INSERT"), New TypedValue(2, "blockname1,blockname2,blockname3,")} Dim psr As PromptSelectionResult = ed.SelectAll(New SelectionFilter(filter)) If psr.Status = PromptStatus.OK Then Return End If
Thanks conormccartney3897. I am no longer intrested in this approach as the .NET app developing for my small size drawing office looks like to be a ridiculously tough and challenging task.
I changed my mind from .NET to Visual LISP.
I know that I will loose the joy of Visual Studio coding but I will get rid of lots of mysterious errors and behaviours toward makeing a safe communication between AutoCAD and my EXE application.
The current and new obstacle, for me, is to model the same functionalities that I previously had in my EXE application into LISP.
I may bother you guys again in other threads 😉
Can't find what you're looking for? Ask the community or share your knowledge.