Author Topic: One sub to process multiple types VB.NET  (Read 3486 times)

0 Members and 1 Guest are viewing this topic.

slappy

  • Guest
One sub to process multiple types VB.NET
« on: February 23, 2012, 04:00:18 PM »
Doing an annotation mod script and I need it to add/remove annotation scales for ALL annotatible objects.  Now for the most part I think I have a working code.... I hope.  But looking over my code I see alot of duplication that seems like it could be combined into a multi-tasking sub.

I want a single sub that can use multiple types without multiple branching into duplicate code.

Types are:
DBObjects
BlockReference
Entity: non-attributes inside blocks
AttributeReference

once each item is identified as annotative it gets processed to add the cannoscale and all others get deleted.  Ideas and Code from Kean Walmsley

Here is the code:
Code - vb.net: [Select]
  1. Imports Autodesk.AutoCAD
  2. Imports Autodesk.AutoCAD.Runtime
  3. Imports Autodesk.AutoCAD.ApplicationServices
  4. Imports Autodesk.AutoCAD.DatabaseServices
  5. Imports Autodesk.AutoCAD.EditorInput
  6. Public Class AnnoControl
  7.     <CommandMethod("AddCanno")> _
  8.     Public Sub annoMod()
  9.         Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor
  10.         Dim db As Database = HostApplicationServices.WorkingDatabase
  11.         Dim prmptSelOp As New PromptSelectionOptions()
  12.         prmptSelOp.MessageForAdding = vbLf & "Select annotative objects"
  13.         Dim prmptSelRes As PromptSelectionResult = ed.GetSelection(prmptSelOp)
  14.         If prmptSelRes.Status <> PromptStatus.OK Then
  15.             Return
  16.         End If
  17.         Dim pKeyword As PromptKeywordOptions = New PromptKeywordOptions("")
  18.         pKeyword.Message = vbLf & "Delete non-current scales?"
  19.         pKeyword.Keywords.Add("Yes")
  20.         pKeyword.Keywords.Add("No")
  21.         pKeyword.Keywords.Default = "Yes"
  22.         pKeyword.AllowNone = False
  23.         Dim pResult As PromptResult = ed.GetKeywords(pKeyword)
  24.  
  25.         Dim tr As Transaction = db.TransactionManager.StartTransaction()
  26.         Try
  27.             Dim dwgAnnoScle As ObjectContextCollection = CurAScale(True)
  28.             Dim cAnnoScle As ObjectContext = CurAScale()
  29.             'Process selceted items
  30.             For Each selObject As SelectedObject In prmptSelRes.Value
  31.                 Dim selObjectID As ObjectId = selObject.ObjectId
  32.                 'Check if items are blocks
  33.                 If selObjectID.ObjectClass.DxfName = "INSERT" Then
  34.                     Dim blkRef As BlockReference = DirectCast(tr.GetObject(selObjectID, OpenMode.ForRead), BlockReference)
  35.                     Dim btr As BlockTableRecord = DirectCast(tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)
  36.                     'if block is not annotative check the blocks contents for annotative objects
  37.                     If blkRef.Annotative = AnnotativeStates.[False] Then
  38.                         For Each btrID As ObjectId In btr
  39.                             Dim ent As Entity = tr.GetObject(btrID, OpenMode.ForRead)
  40.                             'ignore if attribute (handles later)
  41.                             If TypeOf (ent) Is AttributeDefinition Then
  42.                                 Continue For
  43.                                 'check if annotative and does not have current anno state
  44.                             ElseIf ent.Annotative = AnnotativeStates.[True] AndAlso ent.HasContext(cAnnoScle) = False Then
  45.                                ' Now we get it for write
  46.                                 ent.UpgradeOpen()
  47.                                 ent.AddContext(cAnnoScle)
  48.                                 If pResult.StringResult = "Yes" Then
  49.                                     For Each oc As ObjectContext In dwgAnnoScle
  50.                                         If ent.HasContext(oc) AndAlso oc.Name <> db.Cannoscale.Name Then
  51.                                             ' Remove it non-current scale
  52.                                             ent.RemoveContext(oc)
  53.                                         End If
  54.                                     Next
  55.                                 End If
  56.                             End If
  57.                         Next                        'process attributes
  58.                         Dim attCol As AttributeCollection = blkRef.AttributeCollection
  59.                         For Each attId As ObjectId In attCol
  60.                             Dim attRef As AttributeReference = DirectCast(tr.GetObject(attId, OpenMode.ForRead), AttributeReference)
  61.                             'check if annotative and does not have current anno state
  62.                             If attRef.Annotative = AnnotativeStates.[True] AndAlso attRef.HasContext(cAnnoScle) = False Then
  63.                                 attRef.UpgradeOpen()
  64.                                 ' Add Cannoscale
  65.                                 attRef.AddContext(cAnnoScle)
  66.                                 ' Remove it non-current scales
  67.                                 If pResult.StringResult = "Yes" Then
  68.                                     For Each oc As ObjectContext In dwgAnnoScle
  69.                                         If attRef.HasContext(oc) AndAlso oc.Name <> db.Cannoscale.Name Then
  70.                                             attRef.RemoveContext(oc)
  71.                                         End If
  72.                                     Next
  73.                                 End If
  74.                             End If
  75.                         Next
  76.                         'process annotative blocks
  77.                         'check if annotative and does not have current anno state
  78.                     ElseIf blkRef.Annotative = AnnotativeStates.[True] AndAlso blkRef.HasContext(cAnnoScle) = False Then
  79.                         blkRef.UpgradeOpen()
  80.                         blkRef.AddContext(cAnnoScle)
  81.                         If pResult.StringResult = "Yes" Then
  82.                             For Each oc As ObjectContext In dwgAnnoScle
  83.                                 If blkRef.HasContext(oc) AndAlso oc.Name <> db.Cannoscale.Name Then
  84.                                     blkRef.RemoveContext(oc)
  85.                                 End If
  86.                             Next
  87.                         End If
  88.                     End If
  89.                 Else
  90.                     'process all other annotative blocks
  91.                     Dim annoObj As DBObject = tr.GetObject(selObjectID, OpenMode.ForRead)
  92.                     If annoObj.Annotative = AnnotativeStates.[True] AndAlso annoObj.HasContext(cAnnoScle) = False Then
  93.                         annoObj.UpgradeOpen()
  94.                         annoObj.AddContext(CurAScale)
  95.                         If pResult.StringResult = "Yes" Then
  96.                             For Each oc As ObjectContext In dwgAnnoScle
  97.                                 If annoObj.HasContext(oc) AndAlso oc.Name <> db.Cannoscale.Name Then
  98.                                     annoObj.RemoveContext(oc)
  99.                                 End If
  100.                             Next
  101.                         End If
  102.                     End If
  103.                 End If
  104.             Next
  105.             tr.Commit()
  106.         Catch ex As Autodesk.AutoCAD.Runtime.Exception
  107.             ed.WriteMessage(("Exception: " + ex.Message))
  108.         Finally
  109.             tr.Dispose()
  110.         End Try
  111.     End Sub
  112.     Public Shared Function CurAScale(Optional ByVal collection As Boolean = False) 'As ObjectContext
  113.         Dim db As Database = Application.DocumentManager.MdiActiveDocument.Database
  114.         ' Get the manager object and the list of scales
  115.         Dim ocm As ObjectContextManager = db.ObjectContextManager
  116.         Dim occ As ObjectContextCollection = ocm.GetContextCollection("ACDB_ANNOTATIONSCALES")
  117.         If Not occ.HasContext(db.Cannoscale.Name) Then
  118.             DialMessExcep.OKException(vbLf & "Cannot find current annotation scale.")
  119.             Return Nothing
  120.         ElseIf collection = True Then
  121.             Return occ
  122.         Else
  123.             Dim curCtxt As ObjectContext = occ.GetContext(db.Cannoscale.Name)
  124.             Return curCtxt
  125.         End If
  126.     End Function
  127.  
  128. End Class
Let me know what you think
Feel free to call me crap coder... Cuz I know already. :|

edit kdub: formatting to code=vbnet
« Last Edit: February 23, 2012, 05:38:54 PM by Kerry »

kaefer

  • Guest
Re: One sub to process multiple types VB.NET
« Reply #1 on: February 23, 2012, 06:34:23 PM »
I want a single sub that can use multiple types without multiple branching into duplicate code.

You may want a single function which takes an Entity (or any of its subtypes). You do not loose any annotation scales on DBObject (which has no graphical representation anyway). In fact, you have it right there:

Quote
Code: [Select]
  39.                                 Dim ent As Entity = tr.GetObject(btrID, OpenMode.ForRead)
...
  44.                                 ElseIf ent.Annotative = AnnotativeStates.[True] AndAlso ent.HasContext(cAnnoScle) = False Then
  45.                                    ' Now we get it for write
  46.                                     ent.UpgradeOpen()
  47.                                     ent.AddContext(cAnnoScle)
  48.                                     If pResult.StringResult = "Yes" Then
  49.                                         For Each oc As ObjectContext In dwgAnnoScle
  50.                                             If ent.HasContext(oc) AndAlso oc.Name <> db.Cannoscale.Name Then
  51.                                                 ' Remove it non-current scale
  52.                                                 ent.RemoveContext(oc)
  53.                                             End If
  54.                                         Next
  55.                                     End If
  56.                                 End If

slappy

  • Guest
Re: One sub to process multiple types VB.NET
« Reply #2 on: February 24, 2012, 09:46:35 AM »
Thanks kaefer, I'll play around with it.

kaefer

  • Guest
Re: One sub to process multiple types VB.NET
« Reply #3 on: February 24, 2012, 11:33:40 AM »
In addition to enforcing the DRY principle you could also tweak the part of your code determining if it's a Block Reference or merely an Entity, like this:
Code - vb.net: [Select]
  1.            For Each selObject As SelectedObject In prmptSelRes.Value
  2.                 Dim ent = TryCast(selObject.ObjectId.GetObject(OpenMode.ForRead), Entity)
  3.                 If ent Is Nothing Then Continue For
  4.                 Dim blkref = TryCast(ent, BlockReference)
  5.                 'Check if items are blocks
  6.                 If blkref IsNot Nothing Then
  7.                     'it's a BlockReference
  8.                 Else
  9.                     'it's an Entity
  10.                 End If

slappy

  • Guest
Re: One sub to process multiple types VB.NET
« Reply #4 on: February 24, 2012, 12:08:18 PM »
That's nice!
I was thinking along those same lines.  Setting ent earlier simplifies alot.

Is is safe to assume TryCast is the better approach here because if it fails it returns nothing, versus a DirectCast which may error out?  Although I can see the need to catch DirectCast error in other scenarios.

By the way, I have utilized Entity and it's works like a charm.  Thanks again.  I didn't realize Entity was so versitile.  Does it come with the same stygma as using "Object" type?

I think my biggest problem is knowing what type uses are appropriate.  All my experience is trial by fire.

dgorsman

  • Water Moccasin
  • Posts: 2437
Re: One sub to process multiple types VB.NET
« Reply #5 on: February 24, 2012, 12:43:21 PM »
Possibly implement an abstract base class with some static members for common methods to all plus some abstract methods for placeholders, and inherit to specific-object classes which contain methods, properties, and overrides needed to handle their unique characteristics.  Or for something more linear, overload a static method with different types as arguments, with the common bits referencing private methods.
If you are going to fly by the seat of your pants, expect friction burns.

try {GreatPower;}
   catch (notResponsible)
      {NextTime(PlanAhead);}
   finally
      {MasterBasics;}

slappy

  • Guest
Re: One sub to process multiple types VB.NET
« Reply #6 on: February 24, 2012, 01:04:27 PM »
Possibly implement an abstract base class with some static members for common methods to all plus some abstract methods for placeholders, and inherit to specific-object classes which contain methods, properties, and overrides needed to handle their unique characteristics.  Or for something more linear, overload a static method with different types as arguments, with the common bits referencing private methods.

Great idea!  I'll get back to you on that.    :?

slappy

  • Guest
Re: One sub to process multiple types VB.NET
« Reply #7 on: February 24, 2012, 06:00:03 PM »
hmm, cursing along everything seems to be working well.  Then BAM.

For some reason it doesn't want to refresh nested dimensions...  It adds the scale just fine but the dim doesn't visually show the change.  If I edit the block and then edit the dim text (in Autocad) the dim will update, but not before.

Regular dimensions seem to work fine, jus those nested ones.  Hatches are good, text, anno blocks, etc all update as normal inside the block, just the dimensions.  Is there something special about them?  Some special dimension type I should use to process dimension in blocks?