.NET

Reply
Active Contributor
xdbk07
Posts: 42
Registered: ‎11-06-2012
Message 1 of 9 (363 Views)
Accepted Solution

Sum ATT value of blockreference

363 Views, 8 Replies
03-08-2013 12:43 AM

Hi All,

 

Do we have any way to sum attribute value (integer) of many blocks fast?. 

 

Thanks,

Here is complete working code

I've used blocks "Panel" for test

Change them to your suit:

 <CommandMethod("summa", CommandFlags.UsePickSet)> _
Public Shared Sub SUM_AttBlk()
Dim acName As String = ""
Dim acQty As Integer = 0
Dim acDet As String = ""
Dim acDes As String = ""
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(1) {New TypedValue(0, "INSERT"), New TypedValue(2, "Panel")}
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 blockData As List(Of Object()) = New List(Of Object())
Dim blockData As New ArrayList
Dim idArray As ObjectId() = selSet.GetObjectIds()
For Each blkId As ObjectId In idArray
Dim blkRef As BlockReference = tr.GetObject(blkId, OpenMode.ForRead)
Dim attCol As AttributeCollection = blkRef.AttributeCollection
For Each attId As ObjectId In attCol
Dim attRef As AttributeReference = DirectCast(tr.GetObject(attId, OpenMode.ForRead), AttributeReference)
If (attRef.Tag = "NAME") Then
acName = attRef.TextString
ElseIf (attRef.Tag = "DETAIL") Then
acDet = attRef.TextString
ElseIf (attRef.Tag = "DES") Then
acDes = attRef.TextString
ElseIf (attRef.Tag = "QTY") Then
acQty = Convert.ToInt32(attRef.TextString)
End If
Dim tmpData() As Object = New Object(3) {}
tmpData(0) = acName
tmpData(1) = acDet
tmpData(2) = acDes
tmpData(3) = acQty
Next
blockData.Add(New Object() {acName, acDet, acDes, acQty})
Next
Dim grop_query = (From el In blockData _
Group el By key = el(0) + "," + el(1) Into Group, qty = Sum(Convert.ToDecimal(el(3))) _
Select dt = key, total = qty).ToList()
Dim sb As New StringBuilder
For Each grp In grop_query
Dim keys() As String = grp.dt.Split(","c)
'Console.WriteLine(keys(0) + vbTab + keys(1)) 'ok
sb.AppendLine(keys(0) & vbTab & keys(1) & vbTab & grp.total)
Next
MsgBox("Block info:" & vbLf & sb.ToString)
tr.Commit()
Catch ex As Autodesk.AutoCAD.Runtime.Exception
MsgBox("Exception: " + ex.Message + vbLf + ex.ErrorStatus)
tr.Abort()
Finally
tr.Dispose()
End Try
End Sub

 

Hi Hallex,

 

 

How to display acDes value after query?

 

Thanks,

*Expert Elite*
norman.yuan
Posts: 998
Registered: ‎04-27-2009
Message 2 of 9 (339 Views)

Re: Sum ATT value of blockreference

03-08-2013 07:09 AM in reply to: xdbk07

Would you care to clarify what exactly you need to know?

 

Is it that you know a few ways of doing it but want to know which is fast or faster? Or you you just want to know whether it can be done (of course it can)? How much do you know .NET API programming? Or by "fast", you actually meant for quick, simple code, rather than running speed.

 

Yes, there is way to sum up value of ATT of one or more blocks. Yes, it could be fast or slow, deponding on the drawing size, block counts to be searched...It could be a fraction of seconds to who knows how long.

 

Basically, you would have code to identify one or more blocks by either asking user to select on drawing, or by searching drawing with certain criteria (block name, attribute tag...), then in a transaction, you open each block references, loop through its attribute collection and convert the targeting attribute value to a number and sum it up.

Active Contributor
xdbk07
Posts: 42
Registered: ‎11-06-2012
Message 3 of 9 (324 Views)

Re: Sum ATT value of blockreference

03-08-2013 04:32 PM in reply to: norman.yuan

Thank for reply. 

I have a large quantity of blocks. Each of block has 4 tag (Name-Detail-Description-Quantity). This code I  get blocks:

Public Sub SUM_AttBlk()
        Dim acName As String = ""
        Dim acQty As Integer=0
        Dim acDet As String = ""
        Dim acDes As String = ""

        Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
        Dim db As Database = HostApplicationServices.WorkingDatabase
        Dim tr As Transaction = db.TransactionManager.StartTransaction()
        Try
            Dim filList AsTypedValue() = 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 = tr.GetObject(blkId, OpenMode.ForRead)

                Dim attCol AsAttributeCollection = blkRef.AttributeCollection

                For Each attId As ObjectId In attCol
                    Dim attRef As AttributeReference = DirectCast(tr.GetObject(attId, OpenMode.ForRead),AttributeReference)
                    If (attRef.Tag = "NAME") Then
                        acName = attRef.TextString
                    ElseIf (attRef.Tag = "DETAIL") Then
                        acDet = attRef.TextString
                    ElseIf (attRef.Tag = "DES") Then
                        acDes = attRef.TextString
                    ElseIf (attRef.Tag = "QTY") Then
                        acQty = Convert.ToInt32(attRef.TextString)
                    End If
                Next
            Next
            tr.Commit()
        Catch ex As Autodesk.AutoCAD.Runtime.Exception
            MsgBox(("Exception: " + ex.Message + ex.ErrorStatus))
        Finally
            tr.Dispose()
        End Try
    End Sub

 

I want to sum them base on name and detail. If block has same name and detail we sum quantity.

Finally, display result on form. if blocks have same name and detail displayed uniquely.

 

Thanks,

*Expert Elite*
Hallex
Posts: 1,569
Registered: ‎10-08-2008
Message 4 of 9 (288 Views)

Re: Sum ATT value of blockreference

03-10-2013 05:03 AM in reply to: xdbk07

Try this pseudo-code snip

''gather your block attribute values into ArraylList
 Dim list As ArrayList = New ArrayList()
        For Each attId As ObjectId In attCol
                    Dim attRef As AttributeReference = DirectCast(tr.GetObject(attId, OpenMode.ForRead),AttributeReference)
                    If (attRef.Tag = "NAME") Then
                        acName = attRef.TextString
                    ElseIf (attRef.Tag = "DETAIL") Then
                        acDet = attRef.TextString
                    ElseIf (attRef.Tag = "DES") Then
                        acDes = attRef.TextString
                    ElseIf (attRef.Tag = "QTY") Then
                        acQty = Convert.ToInt32(attRef.TextString)
                    End If
                Next
list.Add(New Object() {acName, acDet, acDes,  acQty})
            Next
'then aplly Linq-based expression to do your job, e.g.:
Dim grop_query = (From el In list _
                   Group el By key = el(0) + "," + el(1) Into Group, qty = Sum(Convert.ToDecimal(el(3))) _
                   Select dt = key, total = qty).ToList()
'just to display result of query:
            Dim sb As New StringBuilder
            For Each grp In grop_query
                Dim keys() As String = grp.dt.Split(","c)
                'Console.WriteLine(keys(0) + vbTab + keys(1)) 'ok
                sb.AppendLine(keys(0) & vbTab & keys(1) & vbTab & grp.total)' description is ommited, add them if you need
            Next
            MsgBox("Block info:" & vbLf & sb.ToString)
' You have instead to pull this data in the table data list (of string) or in arralist

 Not tested, just from the top of my head :smileyhappy:

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Active Contributor
xdbk07
Posts: 42
Registered: ‎11-06-2012
Message 5 of 9 (281 Views)

Re: Sum ATT value of blockreference

03-10-2013 08:44 AM in reply to: xdbk07

Hi Hallex,

There is an err in this line:

Dim grop_query = (From el In List Group el By key = el(0) + "," + el(1) Into Group, qty = Sum(Convert.ToDecimal(el(3))) Select dt = key, total = qty).ToList()

 

Err Description:

"Too few type arguments to 'System.Collections.Generic.List(of T)

 

What happen?

 

Thanks,

 

 

*Expert Elite*
Hallex
Posts: 1,569
Registered: ‎10-08-2008
Message 6 of 9 (278 Views)

Re: Sum ATT value of blockreference

03-10-2013 08:54 AM in reply to: xdbk07

I don't know why,

It's working good on my A2010 Net.Framework 3.5

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Active Contributor
xdbk07
Posts: 42
Registered: ‎11-06-2012
Message 7 of 9 (275 Views)

Re: Sum ATT value of blockreference

03-10-2013 08:59 AM in reply to: Hallex

I use Autocad 2012 and VS2010. Please see attachment.

Thanks,

*Expert Elite*
Hallex
Posts: 1,569
Registered: ‎10-08-2008
Message 8 of 9 (266 Views)

Re: Sum ATT value of blockreference

03-10-2013 10:14 AM in reply to: xdbk07

Here is complete working code

I've used blocks "Panel" for test

Change them to your suit:

        <CommandMethod("summa", CommandFlags.UsePickSet)> _
        Public Shared Sub SUM_AttBlk()
            Dim acName As String = ""
            Dim acQty As Integer = 0
            Dim acDet As String = ""
            Dim acDes As String = ""

            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(1) {New TypedValue(0, "INSERT"), New TypedValue(2, "Panel")}
                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 blockData As List(Of Object()) = New List(Of Object())
                Dim blockData As New ArrayList
                Dim idArray As ObjectId() = selSet.GetObjectIds()

                For Each blkId As ObjectId In idArray

                    Dim blkRef As BlockReference = tr.GetObject(blkId, OpenMode.ForRead)

                    Dim attCol As AttributeCollection = blkRef.AttributeCollection

                    For Each attId As ObjectId In attCol
                        Dim attRef As AttributeReference = DirectCast(tr.GetObject(attId, OpenMode.ForRead), AttributeReference)
                        If (attRef.Tag = "NAME") Then
                            acName = attRef.TextString
                        ElseIf (attRef.Tag = "DETAIL") Then
                            acDet = attRef.TextString
                        ElseIf (attRef.Tag = "DES") Then
                            acDes = attRef.TextString
                        ElseIf (attRef.Tag = "QTY") Then
                            acQty = Convert.ToInt32(attRef.TextString)
                        End If
                        Dim tmpData() As Object = New Object(3) {}
                        tmpData(0) = acName
                        tmpData(1) = acDet
                        tmpData(2) = acDes
                        tmpData(3) = acQty

                    Next
                    blockData.Add(New Object() {acName, acDet, acDes, acQty})
                Next
                Dim grop_query = (From el In blockData _
               Group el By key = el(0) + "," + el(1) Into Group, qty = Sum(Convert.ToDecimal(el(3))) _
               Select dt = key, total = qty).ToList()
                Dim sb As New StringBuilder
                For Each grp In grop_query
                    Dim keys() As String = grp.dt.Split(","c)
                    'Console.WriteLine(keys(0) + vbTab + keys(1)) 'ok
                    sb.AppendLine(keys(0) & vbTab & keys(1) & vbTab & grp.total)
                Next
                MsgBox("Block info:" & vbLf & sb.ToString)
           
                tr.Commit()
            Catch ex As Autodesk.AutoCAD.Runtime.Exception
                MsgBox("Exception: " + ex.Message + vbLf + ex.ErrorStatus)
                tr.Abort()
            Finally
                tr.Dispose()
            End Try
        End Sub

 

_____________________________________
C6309D9E0751D165D0934D0621DFF27919
Active Contributor
xdbk07
Posts: 42
Registered: ‎11-06-2012
Message 9 of 9 (192 Views)

Re: Sum ATT value of blockreference

03-16-2013 04:18 AM in reply to: Hallex

Hi Hallex,

 

 

How to display acDes value after query?

 

Thanks,

Announcements
Are you familiar with the Autodesk Expert Elites? The Expert Elite program is made up of customers that help other customers by sharing knowledge and exemplifying an engaging style of collaboration. To learn more, please visit our Expert Elite website.
Need installation help?

Start with some of our most frequented solutions or visit the Installation and Licensing Forum to get help installing your software.