I'm sure many Swampers(?) will be familiar with the Update lisp routine that reads attributes in from CSV files to (usually) titleblocks? See below for my version of this written in VB, with the extended functionality of it being able to update multi-layout drawing files and target a specific block by name. The majority of the layout iteration is taken from
http://dwgdotnet.blogspot.com/2008/07/finding-all-title-blocks-on-all-layouts.html - can't remember where I got the CSV reader from...
For this to work, you mostly need the same pre-requisites as the lisp version:
1. A txt file named RegisterPointer.txt in the same folder as the dwg file, this contains a single line with the full name (directory path, filename and extension) of the CSV.
2. A CSV file containing your titleblock info with specific layout names in column B, with attribute tags being defined in the first row
3. A txt file named "Title Text Block" in the same folder as your CSV file with the block name you wish to update. This file contains a single line with the block name to be updated.
To re-confirm -
this works off individual layout names listed in the CSV's column B and is independent of the drawing name.This is provided "as is", feel free to use/improve/constructively criticize!
<CommandMethod("Update")> _
Public Sub Update()
' Get the current document database and active drawing
Dim oDb As Database = HostApplicationServices.WorkingDatabase
Dim oDwg As Autodesk.AutoCAD.ApplicationServices.Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
Dim oEd As Editor = oDwg.Editor
Dim ed As Autodesk.AutoCAD.EditorInput.Editor = oDwg.Editor
Dim strThisDrawing As String = oDwg.Name
Dim strThisDrawingNoExt As String = Path.GetFileNameWithoutExtension(strThisDrawing)
Dim strThisPath As String = Path.GetDirectoryName(strThisDrawing)
Dim strPointerFile As String = strThisPath + "\RegisterPointer.txt"
Dim dstRegisterInfo As DataSet = Nothing
Dim xlsArrayList As ArrayList = Nothing
Dim dstSettingsInfo As DataSet = Nothing
Dim lstAttributeTags As New ArrayList
Dim lstAttributeTexts As New ArrayList
Dim strLayoutName As String
Dim intAttCount As String = 0
Dim strTextBlock As String = Nothing
Dim strPointedFile As String
Dim blnSkipLayout As Boolean ' this value is toggled depending on whether there is any entry in the register for the active layout
blnSkipLayout = True
If File.Exists(strPointerFile) = True Then
Dim objStreamReader As New StreamReader(strPointerFile)
strPointedFile = objStreamReader.ReadLine
dstRegisterInfo = ReadFromCSV(strPointedFile) ' grab the information from the Excel register
Try
strTextBlock = GetTitleText(strPointedFile) ' grab the title text block name from the txt file in the same folder as the register
Catch
oEd.WriteMessage(Environment.NewLine & "No Title Text Block txt File Detected")
Exit Sub
End Try
Else
oEd.WriteMessage(Environment.NewLine & "No Pointer File Detected")
Exit Sub
End If
For Each dt As System.Data.DataTable In dstRegisterInfo.Tables
For Each dc As System.Data.DataColumn In dt.Columns
lstAttributeTags.Add(dc.ColumnName)
Next
Next
' Start a transaction
Dim oTrans As Transaction = oDb.TransactionManager.StartTransaction
' Get the current layout id and layout name
Dim curLayoutID As ObjectId = LayoutManager.Current.GetLayoutId(LayoutManager.Current.CurrentLayout)
Dim curLayout As Layout = CType(curLayoutID.GetObject(OpenMode.ForRead), Layout)
' Create an arraylist to store our layout entity ids in
Dim oTblocks As New ArrayList
Try ' Lock the drawing
Using locked As Autodesk.AutoCAD.ApplicationServices.DocumentLock = oDwg.LockDocument()
' Get the drawings layout dictionary
Dim layoutDict As DBDictionary = CType(oTrans.GetObject(oDb.LayoutDictionaryId, OpenMode.ForRead), DBDictionary)
Dim indexTb As Integer = 1
For Each id As DictionaryEntry In layoutDict ' iterate through all the drawing layouts
strLayoutName = id.Key.ToString ' the id.key is the layout name
If Not strLayoutName = "Model" Then ' Ignore modelspace
blnSkipLayout = True
lstAttributeTexts.Clear() ' clear array from possible previous run
For Each dt As System.Data.DataTable In dstRegisterInfo.Tables ' populate an array with the relevant attribute textstrings, depending on the current layout
For Each dr As System.Data.DataRow In dt.Rows
If Not dr(1).ToString = Nothing Then
If dr(1).ToString = strLayoutName Then
blnSkipLayout = False
For Each item In dr.ItemArray
lstAttributeTexts.Add(item.ToString)
Next
End If
End If
Next
Next
If blnSkipLayout = False Then
Dim oLayout As Layout = CType(oTrans.GetObject(CType(id.Value, ObjectId), OpenMode.ForRead), Layout) ' use the layouts ID to grab the layout
Dim oBtr As BlockTableRecord = CType(oTrans.GetObject(oLayout.BlockTableRecordId, OpenMode.ForRead, False), BlockTableRecord) ' get the layouts block table
Dim oBtre As BlockTableRecordEnumerator = oBtr.GetEnumerator ' get the block table's enumerator
While oBtre.MoveNext ' iterate through the enumerator
Dim oEnt As Entity = CType(oTrans.GetObject(oBtre.Current, OpenMode.ForRead), Entity)
If TypeOf oEnt Is BlockReference Then ' if its a block reference
Dim oBr As BlockReference = CType(oEnt, BlockReference)
If oBr.Name.Equals(strTextBlock) Then ' if its name matches the title text block name
Dim oDoId As ObjectId = oBr.ObjectId ' get the references object id
Dim attRefIds As AttributeCollection = oBr.AttributeCollection ' get its attribute collection
For Each attRefID As ObjectId In attRefIds ' iterate through the attributes
Dim attref As AttributeReference = CType(oTrans.GetObject(attRefID, OpenMode.ForWrite, False), AttributeReference) ' open each attribute for write
For intLoop As Integer = 0 To lstAttributeTags.Count - 1 ' loop through the known number of attributes as provided by the Excel sheet
If lstAttributeTags(intLoop).ToString = attref.Tag.ToString Then ' if the current attribute matches the array entry
If lstAttributeTexts.Count <= lstAttributeTags.Count Then
attref.TextString = lstAttributeTexts(intLoop).ToString ' change the textstring to the array entry
End If
intAttCount = intAttCount + 1
End If
Next
Next
End If
End If
End While
End If
End If
Next
End Using
ed.Regen()
oTrans.Commit()
Catch ex As System.Exception
MsgBox(ex.Message, MsgBoxStyle.Information, "Error")
Finally
oEd.WriteMessage(Environment.NewLine & "Update Complete. " & intAttCount.ToString & " Attributes Updated")
oTrans.Dispose()
End Try
End Sub
Private Function GetTitleText(ByVal Register As String)
Dim strTitleTextFile As String
Dim strTitleTextBlockName As String
Dim strThisPath As String = Path.GetDirectoryName(Register)
strTitleTextFile = strThisPath + "\Title Text Block.txt"
Dim objStreamReader As New StreamReader(strTitleTextFile)
strTitleTextBlockName = objStreamReader.ReadLine
Return strTitleTextBlockName
End Function
Private Function ReadFromCSV(ByVal CSVFile As String)
Dim strLine As String
Dim strArray() As String
Dim ds As DataSet = New DataSet
Dim dt As System.Data.DataTable = ds.Tables.Add("TheData")
Dim aFile As FileStream = New FileStream(CSVFile, FileMode.Open)
Dim sr As StreamReader = New StreamReader(aFile)
strLine = sr.ReadLine
strArray = Split(strLine, ",")
Dim x As Integer
Dim y As Integer = strArray.GetUpperBound(0)
For x = 0 To y
dt.Columns.Add(strArray(x).Trim())
Next
strLine = sr.ReadLine
While Not strLine = Nothing
strArray = Split(strLine, ",")
Dim dr As DataRow = dt.NewRow
For c As Integer = 0 To strArray.GetUpperBound(0)
dr(c) = strArray(c).Trim()
Next
dt.Rows.Add(dr)
strLine = sr.ReadLine
End While
sr.Close()
Return ds
End Function