Author Topic: Block Replace / Value Xfer VB.NET Bombs: Same Block Name w/ Different Tags  (Read 5740 times)

0 Members and 1 Guest are viewing this topic.

Chillme1

  • Newt
  • Posts: 57
  • Must learn to earn!
I requested assistance with a block attribute value transfer routine that uses an XML file that as the source of matches between old and new blocks.
The XML file also holds matching attribute tag listings between each set of old and new blocks.

The program is thoroughly tested and worked perfectly on blocks while picking from among the blocks with different file names.

The problem is introduced when this program is run in trying to transfer the values from an old to a new version of a similarly named block.
The difference between the old and new version of the similarly named block lies in a handful of attribute tag names.

I attempted to define all matching tag names in the XML but I am not sure if the issue is in the VB code or in the XML file contents.
I am a novice and learning how to use, diagnose, and correct code via debugging is painfully slow right now.

Would someone be willing to dissect the otherwise air-tight code by another: a developer and well-known instructor of AutoCAD VB.NET?
Let me know and I'll check back on Monday.

I can supply the VB source code, the XML file, and a 2010 version DWG file at that time.

Thanks,
Clint Hill

« Last Edit: September 28, 2012, 06:31:51 PM by Chillme1 »
Thanks, Clint
Mechanical Designer / Process Piping
AutoCAD Toolsets 2022
Newbie Betimes - LISP Programmer

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Block Replace / Value Xfer VB.NET Bombs: Same Block Name w/ Different Tags
« Reply #1 on: September 28, 2012, 06:41:33 PM »
Quote
similarly named block

How similar ??



Quote
and well-known instructor of AutoCAD VB.NET
Is this his code ??


Quote
I can supply the VB source code, the XML file, and a 2010 version DWG file

This will be required .. unless someone has come across this specific issue previously and cares to share.


« Last Edit: September 28, 2012, 06:44:37 PM by Kerry »
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Block Replace / Value Xfer VB.NET Bombs: Same Block Name w/ Different Tags
« Reply #2 on: September 28, 2012, 07:44:17 PM »
Thinking about it :

If you are using the Block name as an identifier
and you change the definition of the block but keep it's name
why are you surprised that the routine can't find non-existant attributes.
... at least I assume that is the problem.

What are you doing to validate the match ??
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

Chillme1

  • Newt
  • Posts: 57
  • Must learn to earn!
Re: Block Replace / Value Xfer VB.NET Bombs: Same Block Name w/ Different Tags
« Reply #3 on: September 29, 2012, 01:24:07 PM »
AFTER thinking about it...:

It appears that a new block with a unique name will solve this minor problem. :kewl:

Flawed thinking = undesired results.

Thanks, Clint
Mechanical Designer / Process Piping
AutoCAD Toolsets 2022
Newbie Betimes - LISP Programmer

Chillme1

  • Newt
  • Posts: 57
  • Must learn to earn!
A little help in briefly perusing the code would be nice as I am a newbie at programming. Coding was largely by my VB.NET instructor (who shall remain nameless here) I would prefer not to bug for a while in further examining this code.
Please know he is very experienced at coding; had thoroughly tested, and had this program working well at the end of our help session.


Your kind assistance is required:
I would like to know if the error lies within the code or in the formatting of the entries in the attached XML support file that is used to store the matches among blocks and attributes.


Code - vb.net: [Select]
  1. Imports System
  2. Imports System.Text
  3. Imports System.IO
  4. Imports System.Data
  5. Imports System.Linq
  6.  
  7. Imports Autodesk.AutoCAD.Runtime
  8. Imports Autodesk.AutoCAD.DatabaseServices
  9. Imports Autodesk.AutoCAD.EditorInput
  10. Imports Autodesk.AutoCAD.Geometry
  11. Imports Autodesk.AutoCAD.ApplicationServices
  12. Imports Autodesk.AutoCAD.Interop
  13. Imports Autodesk.AutoCAD
  14. Imports Autodesk.AutoCAD.ApplicationServices.Application
  15. Imports Autodesk.AutoCAD.LayerManager
  16. Imports Autodesk.AutoCAD.Windows
  17.  
  18. ' This line is not mandatory, but improves loading performances
  19. <Assembly: CommandClass(GetType(TransferAttributes.MyCommands))>
  20.  
  21. Namespace TransferAttributes
  22.  
  23.     ' This class is instantiated by AutoCAD for each document when
  24.     ' a command is called by the user the first time in the context
  25.     ' of a given document. In other words, non static data in this class
  26.     ' is implicitly per-document!
  27.     Public Class MyCommands
  28.  
  29.         <CommandMethod("UpdateAtts")> _
  30.         Public Sub UpdateAtts()
  31.             Dim myDoc As Document = Application.DocumentManager.MdiActiveDocument
  32.             Dim myEd As Editor = myDoc.Editor
  33.             Dim selEntID As ObjectId = myEd.GetEntity("Select Old Block:").ObjectId
  34.             Dim selEntID2 As ObjectId '= myEd.GetEntity("Select New block:").ObjectId
  35.             Dim myXML As New Xml.XmlDocument()
  36.             myXML.Load("c:\i-cad\UpdateAtts_A.xml")
  37.             Using myTrans As Transaction = myDoc.Database.TransactionManager.StartTransaction
  38.                 Dim myBrefA As BlockReference = selEntID.GetObject(OpenMode.ForWrite)
  39.                 Dim myBrefB As BlockReference '= selEntID2.GetObject(OpenMode.ForWrite)
  40.                 Dim myAttsA As AttributeCollection = myBrefA.AttributeCollection
  41.                 Dim myAttsB As AttributeCollection '= myBrefB.AttributeCollection
  42.                 Dim blockNameA As String = ""
  43.                 Dim blockNameB As String = ""
  44.                 If myBrefA.Name.StartsWith("*") Then
  45.                     Dim myBTR As BlockTableRecord = myBrefA.DynamicBlockTableRecord.GetObject(OpenMode.ForRead)
  46.                     blockNameA = myBTR.Name
  47.                 Else
  48.                     blockNameA = myBrefA.Name
  49.                 End If
  50.  
  51.                 Dim oldNode As Xml.XmlNode = myXML.SelectSingleNode("//oldblock[@name='" & blockNameA.ToUpper & "']")
  52.                 Dim myBT As BlockTable = myDoc.Database.BlockTableId.GetObject(OpenMode.ForWrite)
  53.                 If myBT.Has(oldNode.Attributes("newname").Value) = False Then
  54.                     'insert DWG file as a Block
  55.                     Dim myDWG As New IO.FileInfo(oldNode.Attributes("path").Value)
  56.                     If myDWG.Exists = False Then
  57.                         MsgBox("The file " & myDWG.FullName & " does not exist.")
  58.                         Exit Sub
  59.                     End If
  60.                     'Create a blank Database
  61.                     Dim dwgDB As New Database(False, True)
  62.                     'Read a DWG file into the blank database
  63.                     dwgDB.ReadDwgFile(myDWG.FullName, FileOpenMode.OpenForReadAndAllShare, True, "")
  64.                     'insert the dwg file into the current file's block table
  65.                     myDoc.Database.Insert(oldNode.Attributes("newname").Value.ToUpper, dwgDB, True)
  66.                     'close/dispose of the previously blank database.
  67.                     dwgDB.Dispose()
  68.                 End If
  69.                 selEntID2 = InsertBlock(myDoc.Database, myBrefA.BlockName, myBrefA.Position, oldNode.Attributes("newname").Value, myBrefA.ScaleFactors.X, myBrefA.ScaleFactors.Y, myBrefA.ScaleFactors.Z)
  70.                 myBrefB = selEntID2.GetObject(OpenMode.ForWrite)
  71.                 myAttsB = myBrefB.AttributeCollection
  72.                 For Each myNode As Xml.XmlNode In oldNode.SelectNodes("attribute")
  73.                     For Each myAttID As ObjectId In myAttsA
  74.                         Dim myAtt As AttributeReference = myAttID.GetObject(OpenMode.ForRead)
  75.                         If myAtt.Tag.ToUpper = myNode.Attributes("name").Value.ToUpper Then
  76.                             For Each myAttBID As ObjectId In myAttsB
  77.                                 Dim myAttB As AttributeReference = myAttBID.GetObject(OpenMode.ForWrite)
  78.                                 If myAttB.Tag.ToUpper = myNode.Attributes("newname").Value.ToUpper Then
  79.                                     myAttB.TextString = myAtt.TextString
  80.                                 End If
  81.                             Next
  82.                         End If
  83.                     Next
  84.                 Next
  85.                 myBrefA.Erase()
  86.                 myTrans.Commit()
  87.             End Using
  88.  
  89.         End Sub
  90.         Public Function InsertBlock(ByVal DatabaseIn As Database, _
  91.                         ByVal BTRToAddTo As String, _
  92.                         ByVal InsPt As Geometry.Point3d, _
  93.                         ByVal BlockName As String, _
  94.                         ByVal XScale As Double, _
  95.                         ByVal YScale As Double, _
  96.                         ByVal ZScale As Double) As DatabaseServices.ObjectId
  97.             Using myTrans As Transaction = DatabaseIn.TransactionManager.StartTransaction
  98.                 Dim myBlockTable As BlockTable = DatabaseIn.BlockTableId.GetObject(OpenMode.ForRead)
  99.                 'If the suppplied Block Name is not
  100.                 'in the specified Database, get out gracefully.
  101.                 If myBlockTable.Has(BlockName) = False Then
  102.                     Return Nothing
  103.                 End If
  104.                 'If the specified BlockTableRecord does not exist,
  105.                 'get out gracefully
  106.                 If myBlockTable.Has(BTRToAddTo) = False Then
  107.                     Return Nothing
  108.                 End If
  109.                 Dim myBlockDef As BlockTableRecord = _
  110.                     myBlockTable(BlockName).GetObject(OpenMode.ForRead)
  111.                 Dim myBlockTableRecord As BlockTableRecord = _
  112.                     myBlockTable(BTRToAddTo).GetObject(OpenMode.ForWrite)
  113.                 'Create a new BlockReference
  114.                 Dim myBlockRef As New BlockReference(InsPt, myBlockDef.Id)
  115.                 'Set the scale factors
  116.                 myBlockRef.ScaleFactors = New Geometry.Scale3d(XScale, YScale, ZScale)
  117.                 'Add the new BlockReference to the specified BlockTableRecord
  118.                 myBlockTableRecord.AppendEntity(myBlockRef)
  119.                 'Add the BlockReference to the BlockTableRecord.
  120.                 myTrans.AddNewlyCreatedDBObject(myBlockRef, True)
  121.                 Dim myAttColl As DatabaseServices.AttributeCollection = _
  122.                     myBlockRef.AttributeCollection
  123.                 'Find Attributes and add them to the AttributeCollection
  124.                 'of the BlockReference
  125.                 For Each myEntID As ObjectId In myBlockDef
  126.                     Dim myEnt As Entity = myEntID.GetObject(OpenMode.ForRead)
  127.                     If TypeOf myEnt Is DatabaseServices.AttributeDefinition Then
  128.                         Dim myAttDef As DatabaseServices.AttributeDefinition = myEnt
  129.                         Dim myAttRef As New DatabaseServices.AttributeReference
  130.                         myAttRef.SetAttributeFromBlock(myAttDef, myBlockRef.BlockTransform)
  131.                         myAttColl.AppendAttribute(myAttRef)
  132.                         myTrans.AddNewlyCreatedDBObject(myAttRef, True)
  133.                     End If
  134.                 Next
  135.                 myTrans.Commit()
  136.                 Return myBlockRef.Id
  137.             End Using
  138.         End Function
  139.  
Thanks, Clint
Mechanical Designer / Process Piping
AutoCAD Toolsets 2022
Newbie Betimes - LISP Programmer

Chillme1

  • Newt
  • Posts: 57
  • Must learn to earn!
Voila! It works! The problem was in the XML code contents.
Thanks, Clint
Mechanical Designer / Process Piping
AutoCAD Toolsets 2022
Newbie Betimes - LISP Programmer

BlackBox

  • King Gator
  • Posts: 3770
Voila! It works! The problem was in the XML code contents.

Glad you got it sorted; be sure to post an example of the corrected XML format, so others don't get tripped up.
"How we think determines what we do, and what we do determines what we get."

Chillme1

  • Newt
  • Posts: 57
  • Must learn to earn!
That is a great idea and I am more than glad to contribute...

The good code in the XML is as follows:

Code: [Select]
<mapping>
<oldblock name="I-TITLE_B" newname="I-NAS_TITLE_11_x_17" path="C:\I-CAD\I-BLOCKS\Borders\I-NAS_TITLE_11_x_17.dwg">
<attribute name="I-DWGREV" newname="REV"/>
<attribute name="I-DWGDRW" newname="NAME"/>
<attribute name="I-DWGDATE" newname="DATE"/>
<attribute name="I-DWGCHKDATE" newname="CHECKDATE"/>
    <attribute name="I-DWGCHK" newname="CHK"/>
<attribute name="I-DWGTITLE_1" newname="TITLE_1"/>
<attribute name="I-DWGTITLE_2" newname="TITLE_2"/>
<attribute name="I-DWGTITLE_3" newname="TITLE_3"/>
        <attribute name="I-DWGID" newname="DWG_ID"/>
</oldblock>
</mapping>

 HOWEVER, The BAD code in this XML follows:

The routine now doesn't work after code was added below the good code above.
(This code is preceded by the <mapping> statement in the good code above):
   
Code: [Select]
<oldblock name="I-NAS_11_x_17_TITLE_PROCESS_DWGS" newname="I-NAS_TITLE_11_x_17" path="C:\I-CAD\I-BLOCKS\Borders\I-NAS_TITLE_11_x_17.dwg">
<attribute name="REV" newname="REV"/>
<attribute name="NAME" newname="NAME"/>
<attribute name="DATE" newname="DATE"/>
<attribute name="CHECKDATE" newname="CHECKDATE"/>
    <attribute name="CHK" newname="CHK"/>
<attribute name="TITLE_1" newname="TITLE_1"/>
<attribute name="TITLE_2" newname="TITLE_2"/>
<attribute name="TITLE_3" newname="TITLE_3"/>
        <attribute name="DWG_ID" newname="DWG_ID"/>
        <attribute name="SHEET" newname="SHEET"/>
        <attribute name="N_SHEETS" newname="N_SHEETS"/>
        <attribute name="SHT_SIZE" newname="SHT_SIZE"/>
        <attribute name="PLANT_NAM" newname="PLANT_NAM"/>
        <attribute name="PLANT_STR" newname="PLANT_STR"/>
        <attribute name="PLANT_CTY" newname="PLANT_CTY"/>
</oldblock>
</mapping>

Summary
It appears the routine is having trouble with two different block names having the same attribute tag names in this 'bad' XML code snippet.
Could someone verify that is the case and provide a solution?



« Last Edit: October 02, 2012, 02:38:02 PM by Chillme1 »
Thanks, Clint
Mechanical Designer / Process Piping
AutoCAD Toolsets 2022
Newbie Betimes - LISP Programmer

Jeff H

  • Needs a day job
  • Posts: 6150
Looking at the code your VB.NET instructor might of learned from Jerry Winters ;)
 


Also as just some ideas to throw out there, it might be better to create maybe a 'Repository' or something else that seperates data access from data source with block updating code?
 
Would it seem easier not to have all the xml code and block updating code in same method?
 
I would think no matter if from xml file, csv, sql or whatever it should look like a in-memory collection of some ADT like 'BlockInfo'.
 
So you could have easily just thrown a quick hard-coded array at it and found out quickly it was xml.
 
 
 
 

BlackBox

  • King Gator
  • Posts: 3770
Looking at the code your VB.NET instructor might of learned from Jerry Winters ;)

... Isn't Jerry Winters the _only_ AutoCAD VB.NET instructor?  :-D  :whistle:



Separately, I was working on this for my own project in another thread, but it might also be advantageous to incorporate a FileSystemWatcher to monitor the XML file, so that one can make changes, and the 'update' Method is invoked, or the user is notified... To keep everything in Sync.

Example
"How we think determines what we do, and what we do determines what we get."

Chillme1

  • Newt
  • Posts: 57
  • Must learn to earn!
Re: Block Replace / Value Xfer VB.NET Bombs: Same Block Name w/ Different Tags
« Reply #10 on: October 03, 2012, 07:41:24 AM »
Hello Jeff H., Renderman

As in music or painting, there appears to be very definitive styles in coding as well. Well, you can place our esteemed and talented Jerry Winters on the same plane as Vincent Van Gogh or Eddie Van Halen; he is its creator and as masterful, kind and as patient a man as you are.

I would like to approach him with your valued technical comments.
As a mere beginner who is just starting to crawl across code, Greek would be as easy to interpret on my own.

Humbly yours... but I ain't givin' up
Thanks, Clint
Mechanical Designer / Process Piping
AutoCAD Toolsets 2022
Newbie Betimes - LISP Programmer

ReneRam

  • Guest
Re: Block Replace / Value Xfer VB.NET Bombs: Same Block Name w/ Different Tags
« Reply #11 on: October 22, 2012, 06:56:54 AM »
Looking at the code your VB.NET instructor might of learned from Jerry Winters ;)

... Isn't Jerry Winters the _only_ AutoCAD VB.NET instructor?  :-D  :whistle:


Actually I do not think that he is the only Vb instructor, but one of the very few.
Although I must confess that the defects are hard to die, and I too, often, find myself writing in VB without being ashamed.  :kewl: