.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Blocks, attributes and selection sets

10 REPLIES 10
SOLVED
Reply
Message 1 of 11
jaboone
4362 Views, 10 Replies

Blocks, attributes and selection sets

I am just getting into programming a dll inside acad.  Not sure this is the route to go since I have an data object that I need get and incorporate into my dll.  Is there any way to get an object inside a dll from another outside program?

 

I am trying to create a routine that asks for a selection set of lbocks (probably filtered i guess) then serches for a specific attribute tag, which would be a number, then to adds the set of blocks with that attribute value.

 

I have gotten to the part where it ask the user to select some elements which I will filter out the blocks (of many differant block names) the I want to look at a specific attribute tag and add them, if it is valid.  I have a sample which I am just beginning to debug.  The tag name is: DEVICENUMBER, the value is any number.  Could use some help from the experts.  The following code does not work for getting a selection set I need.

 

Public Sub GetSelection()
Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
Dim values() As TypedValue = {New TypedValue(DxfCode.Start, "BLOCK")}'this is where I am having the selection problem
Dim sfilter As New SelectionFilter(values) ' Create the filter using our values...
'Set the selection options
Dim SelOpts As New PromptSelectionOptions()


SelOpts.MessageForAdding = "Select elements:"
SelOpts.AllowDuplicates = True
'Make the selection:
Dim res As PromptSelectionResult = ed.GetSelection(SelOpts, sfilter)

If Not res.Status = PromptStatus.OK Then Return
Dim SS As Autodesk.AutoCAD.EditorInput.SelectionSet = res.Value
Dim idarray As ObjectId() = SS.GetObjectIds()
Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database
Dim tm As Autodesk.AutoCAD.DatabaseServices.TransactionManager = db.TransactionManager
Dim myT As Transaction = tm.StartTransaction()

Try
Dim id As ObjectId
For Each id In idarray
Dim entity As Entity = tm.GetObject(id, OpenMode.ForRead, True)
ed.WriteMessage((ControlChars.Lf + "You selected: " + entity.GetType().FullName))
Next id
Finally
myT.Dispose()
End Try
End Sub

Learning as I go
10 REPLIES 10
Message 2 of 11
norman.yuan
in reply to: jaboone

The entity type in the filter is wrong:

 

Dim values() As TypedValue = {New TypedValue(DxfCode.Start, "BLOCK")}

 

should be

 

Dim values() As TypedValue = {New TypedValue(DxfCode.Start, "INSERT")}

 

So, the returned entities in the SelectionSet will be guaranteed to be BlockReferences. The you loop through each block refernce's AttributeCollection to se if there is/are attribute/attributes with tab "DEVICENUMBER", if yes, set AttributeReference.TextString to the desired number ( a String value).

 

When you go though all the selected block references, you may need to determine if the block is the block you are after, because differnt block may have attribute with the same tag. If all the targeting block is not a dynamic bklock, you can simply add block name into selection filter, so that only blocks with given name is selected. However, if the block is dynamic block, you can only identify targeting block by going through each selected blocks, then test its name, if it is not a dynamic block, or find its name by going after the block refernce's dynamic block definition.

 

As long as you idtentified the block reference is the targeting block, then you can simply:

 

For Each id As ObjectId in theBlockreference.AttrbuteCollection

    Dim att as AttributeReference=tran.GetObject(id, OpenMode.ForRead)

    If att.Tag.ToUpper()=DEVICENUMBER" Then

        att.UpgradeOpen()

        att.TextString=theNumber.ToString()

    End If

Next

Message 3 of 11
jaboone
in reply to: norman.yuan

Thanks Norman  The insert was exactly what I was looking for and see the solution even closer.

I am now hung up on what object the "theBlockreference.AttrbuteCollection" is coming from.  I know you mentioned searching the selection for a collection of the a specific block, but in my case, I want many blocks and want to do a search for an attribute.

 

 

Thank you for your help.

Learning as I go
Message 4 of 11
norman.yuan
in reply to: jaboone

OK, if you do not have to sort out block by name and want to go through all the blocks selected and find Attribute tagged as "DEVICENUMBER", your code will be like:

 

.... ''you cdoe to get selection set

Try
    Dim id As ObjectId
    For Each id In idarray
        Dim blk As BlockReference = myT.GetObject(id, OpenMode.ForRead, True)
        ed.WriteMessage((ControlChars.Lf + "You selected: " + entity.GetType().FullName))

        For Each attId As ObjectId In blk.AttributeCollection

            Dim att As AttributeReference=myT.GetObject(attId,OpenMode.ForRead)

            If att.Tag.ToUpper="DEVICENUMBER" THEN

                att.UpgradeOpen()

                att.textString="12345"

            End If

        Next
   Next id

   myT.Commit() ''Do not forget to commit the transaction!
Finally
 myT.Dispose()
End Try

Message 5 of 11
jaboone
in reply to: norman.yuan

i'm affreaid I'm not having any luck at all with this.  the function does not get past the  for,  so that tells me the logical attid is not valid for that selection set.

I also get The block : *MODEL_SPACE in acad so that tells me I don't have a good selection set either.

 

 

 

Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
Dim values() As TypedValue = {New TypedValue(DxfCode.Start, "INSERT")}
Dim sfilter As New SelectionFilter(values)
Dim SelOpts As New PromptSelectionOptions()


SelOpts.MessageForAdding = "Select receptacle blocks:"
SelOpts.AllowDuplicates = True
'Make the selection:
Dim res As PromptSelectionResult = ed.GetSelection(SelOpts, sfilter)

If Not res.Status = PromptStatus.OK Then Return
Dim SS As Autodesk.AutoCAD.EditorInput.SelectionSet = res.Value
Dim idarray As ObjectId() = SS.GetObjectIds()
Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database
Dim tm As Autodesk.AutoCAD.DatabaseServices.TransactionManager = db.TransactionManager
Dim myT As Transaction = tm.StartTransaction()
Dim x As Integer


Try
Dim id As ObjectId


For Each id In idarray
Dim blk As BlockReference = myT.GetObject(id, OpenMode.ForRead, True)
'ed.WriteMessage((ControlChars.Lf + "You selected: " + Entity.GetType().FullName))
ed.WriteMessage((ControlChars.Lf + "The block: " + blk.BlockName.ToString))
For Each attId As ObjectId In blk.AttributeCollection
Dim att As AttributeReference = myT.GetObject(attId, OpenMode.ForRead)
ed.WriteMessage((", Search: " + att.TextString.ToString))
If att.Tag.ToUpper = "DEVICENUMBER" Then
ed.WriteMessage((", Attribute: " + att.TextString.ToString))
att.UpgradeOpen()
x = Val(att.TextString)
'att.TextString = "12345"
End If
Next
Next id
myT.Commit() ''Do not forget to commit the transaction!
Finally
myT.Dispose()
End Try
txtWatts.Text = x.tostring

Learning as I go
Message 6 of 11
jaboone
in reply to: jaboone

I was able to find some code on a autodesk related web site that had sample code of getting an attribute out of a block.  Not sure why this doesn't work for me since I can't debug the code.  I wish I could becuase that is where I learn the most about what is going on.

 

I selected some blocks with a known attributes in them but the code never printed the attribute tag string telling me that the funtion never got past the second for in this case.  The first print for block name did fine.  Can someone please explain why it never got there when there are attributes in the blocks I had selected?  Is this perhaps searching for plain attribute outside a block?

 

 

<CommandMethod("LISTATT")> _
Public Sub ListAttributes()
Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
Dim db As Database = HostApplicationServices.WorkingDatabase
Dim tr As Transaction = db.TransactionManager.StartTransaction()

' Start the transaction
Try
' Build a filter list so that only
' block references are selected
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)

' Do nothing if selection is unsuccessful
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 & " Attribute Tag: " + attRef.Tag & vbLf & " Attribute String: ") + 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

Learning as I go
Message 7 of 11
norman.yuan
in reply to: jaboone

So your code does selected some block references and can print block name to the command line. The following code that loops through block's AttributeCollection looks good to me. If you step through your code in debugging, it should reveal the reason why the execution does not go inside For Each... of AttributeCollection (You mentioned you cannot debug, why? Writing code without being able to debug is a worst thing one can come to).

 

Are you sure the block selected has attribute in it? Note, if the attribute defined in block definition is constant, the block reference will not have corresponding attribute reference in it. If the block reference is inserted by your .NET code, the attribute reference has to be explicitly created and added into Blockreference's AttributeCollection.

 

So, you can simply add one line code to indicate if there is attributerefence in the block reference or not (well, since you cannot debug for odd, unknown reason):

 

Dim attCol As AttributeCollection = blkRef.AttributeCollection

 

ed.WriteMessage(vbcrlf & "{0} attribute found in block reference.", attCol.Count)

 

Message 8 of 11
jaboone
in reply to: norman.yuan

I figured the problem and thanks for your help Norman.  The attribute was set for constant and I could have sworn I fixed those blocks a while back.  Moved the constant to preset and it works fine now.  That could have been the problem in the first example, but I have to move on now since this is what I want.

 

As far as the debugger is concerned, I am using the vb express version.  If I continue to program more I want to purchase the pro version.  I understand the debugger can not work in Express.

Learning as I go
Message 9 of 11
dgorsman
in reply to: jaboone

I use the C# version of VS Express and I can step through code, halt at break points, inspect/set watches, etc.  Can't edit-and-continue, but my work process kind of minimizes the impact of that limitation.

----------------------------------
If you are going to fly by the seat of your pants, expect friction burns.
"I don't know" is the beginning of knowledge, not the end.


Message 10 of 11
jaboone
in reply to: dgorsman

It should work for me then.  is there a blog for how to do that somewhere or can you tell me how?

Learning as I go
Message 11 of 11
jaboone
in reply to: jaboone

OH, keep in mind that I am creating dll's.

Learning as I go

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost