Editing multiple files

Editing multiple files

WPerciful
Advocate Advocate
1,817 Views
4 Replies
Message 1 of 5

Editing multiple files

WPerciful
Advocate
Advocate

I wrote a tool to perform a find and replace on the active document.  I’ve been attempting to modify it to allow me to pass the sub a file name so that I can perform the edit to multiple files.  As best I can tell the editor variable I set points to the active document.  I simply can’t figure out how to edit the passed document, and not the open one.

 

    Private Sub test(fn As String)
        Dim db As Database = New Database(False, True),
            dwgDir As String = System.IO.Path.GetDirectoryName(fn),
            dwgName As String = System.IO.Path.GetFileName(fn),
            DocMgr As DocumentCollection = Application.DocumentManager,
            Doc As Document = DocumentCollectionExtension.Add(DocMgr, fn),
            ed As Editor = Doc.Editor
        Using db
            Try
                db.ReadDwgFile(fn, FileOpenMode.OpenForReadAndWriteNoShare, False, "")

            Catch __unusedException1__ As System.Exception

                Return
            End Try
            Using tr As Transaction = db.TransactionManager.StartTransaction()
                Dim filList As TypedValue() = New TypedValue(0) {New TypedValue(CInt(DxfCode.Start), "TEXT")},
                    Filter As SelectionFilter = New SelectionFilter(filList),
                    Res As PromptSelectionResult = ed.SelectAll(Filter),
                    selSet As SelectionSet = Res.Value
                If selSet IsNot Nothing Then
                    Dim idArray As ObjectId() = selSet.GetObjectIds()
                    Try
                        For Each txtID As ObjectId In idArray
                            Dim txt As DBText = CType(tr.GetObject(txtID, OpenMode.ForWrite), DBText),
                                    wksp As String = txt.BlockName.ToString,
                                    hand As String = txt.Handle.ToString,
                                    val As String = txt.TextString,
                                    locX As String = txt.Position.X.ToString,
                                    locY As String = txt.Position.Y.ToString,
                                    locZ As String = txt.Position.Z.ToString
                            If hand <> Nothing And val <> Nothing And val.Contains(strFind) Then

                                txt.TextString = val.Replace(strFind, strReplace)
                                txt.RecordGraphicsModified(True)
                                tbl.Rows.Add(txt.TextString, val, "DBText", dwgName, hand, wksp, locX, locY, locZ)
                            End If
                        Next
                        tr.Commit()
                    Catch ex As Autodesk.AutoCAD.Runtime.Exception
                        ed.WriteMessage(("Exception: " & ex.Message))
                    Finally
                        tr.Dispose()
                    End Try
                End If
            End Using

            Using tr As Transaction = db.TransactionManager.StartTransaction()
                Try
                    Dim filList As TypedValue() = New TypedValue(0) {New TypedValue(CInt(DxfCode.Start), "INSERT")},
                            filter As SelectionFilter = New SelectionFilter(filList),
                                    Res As PromptSelectionResult = ed.SelectAll(filter),
                            selSet As SelectionSet = Res.Value
                    If selSet IsNot Nothing Then
                        Dim idArray As ObjectId() = selSet.GetObjectIds()
                        For Each blkId As ObjectId In idArray
                            Dim blkRef As BlockReference = CType(tr.GetObject(blkId, OpenMode.ForRead), BlockReference)
                            Dim BLK_n As String = blkRef.Name,
                                    BLK_hand As String = blkRef.Handle.ToString
                            Dim btr As BlockTableRecord = CType(tr.GetObject(blkRef.BlockTableRecord, OpenMode.ForRead), BlockTableRecord)
                            btr.Dispose()
                            Dim attCol As AttributeCollection = blkRef.AttributeCollection
                            If attCol IsNot Nothing Then
                                For Each attId As ObjectId In attCol
                                    Dim att As AttributeReference = CType(tr.GetObject(attId, OpenMode.ForWrite), AttributeReference),
                                            wksp As String = att.BlockName.ToString,
                                            hand As String = att.Handle.ToString,
                                            val As String = att.TextString,
                                            locX As String = att.Position.X.ToString,
                                            locY As String = att.Position.Y.ToString,
                                            locZ As String = att.Position.Z.ToString
                                    If hand <> Nothing And val <> Nothing And BLK_hand <> Nothing And BLK_n <> Nothing And val.Contains(strFind) = True Then
                                        att.TextString = val.Replace(strFind, strReplace)
                                        att.RecordGraphicsModified(True)
                                        tbl.Rows.Add(att.TextString, val, "Attribute", dwgName, hand, wksp, locX, locY, locZ)

                                    End If
                                Next
                            End If
                        Next
                        tr.Commit()
                    End If
                Catch ex As Autodesk.AutoCAD.Runtime.Exception
                    ed.WriteMessage(("Exception: " & ex.Message))
                Finally
                    tr.Dispose()
                End Try
            End Using

            Using tr As Transaction = db.TransactionManager.StartTransaction()
                Dim filList As TypedValue() = New TypedValue(0) {New TypedValue(CInt(DxfCode.Start), "MTEXT")},
                    Filter As SelectionFilter = New SelectionFilter(filList),
                    Res As PromptSelectionResult = ed.SelectAll(Filter),
                    selSet As SelectionSet = Res.Value
                If selSet IsNot Nothing Then
                    Dim idArray As ObjectId() = selSet.GetObjectIds()
                    Try
                        For Each txtID As ObjectId In idArray
                            Dim mtxt As MText = CType(tr.GetObject(txtID, OpenMode.ForWrite), MText),
                                        wksp As String = mtxt.BlockName.ToString,
                                        hand As String = mtxt.Handle.ToString,
                                        val As String = mtxt.Contents.ToString,
                                        locX As String = mtxt.Location.X.ToString,
                                        locY As String = mtxt.Location.Y.ToString,
                                        locZ As String = mtxt.Location.Z.ToString
                            If hand <> Nothing And val <> Nothing And val.Contains(strFind) = True Then
                                mtxt.Contents = val.Replace(strFind, strReplace)
                                mtxt.RecordGraphicsModified(True)
                                tbl.Rows.Add(mtxt.Contents, val, "MText", dwgName, hand, wksp, locX, locY, locZ)
                            End If
                        Next
                        tr.Commit()
                    Catch ex As Autodesk.AutoCAD.Runtime.Exception
                        ed.WriteMessage(("Exception: " & ex.Message))
                    Finally
                        tr.Dispose()
                    End Try
                End If
            End Using
        End Using



    End Sub

I attempted to approach it differently hoping to resolve the issue, but this code failed too.  It goes through the files but won't update any of them.

 

 

    Private Sub test(fn As String)
        Dim doc As Document = Application.DocumentManager.MdiActiveDocument,
            ed As Editor = doc.Editor,
            db As Database = New Database(False, True),
            dwgDir As String = System.IO.Path.GetDirectoryName(fn),
            dwgName As String = System.IO.Path.GetFileName(fn)

        Using db
            Try
                db.ReadDwgFile(fn, System.IO.FileShare.Read, False, "")
            Catch __unusedException1__ As System.Exception
                ed.WriteMessage(vbLf & "Unable to read drawing file.")
                Return
            End Try

            Dim tr As Transaction = db.TransactionManager.StartTransaction()
            Using tr
                Dim bt As BlockTable = CType(tr.GetObject(db.BlockTableId, OpenMode.ForWrite), BlockTable)
                Dim btr As BlockTableRecord = CType(tr.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead), BlockTableRecord)
                For Each objId As ObjectId In btr
                    Dim objtyp As String = objId.GetType().ToString,
                            objent As Entity = CType(tr.GetObject(objId, OpenMode.ForWrite), Entity),
                            OBJDXF As String = objent.GetRXClass().DxfName
                    Select Case OBJDXF
                        Case "TEXT"
                            Dim txt As DBText = CType(tr.GetObject(objId, OpenMode.ForWrite), DBText),
                                    wksp As String = txt.BlockName.ToString,
                                    hand As String = txt.Handle.ToString,
                                    val As String = txt.TextString,
                                    locX As String = txt.Position.X.ToString,
                                    locY As String = txt.Position.Y.ToString,
                                    locZ As String = txt.Position.Z.ToString
                            If hand <> Nothing And val <> Nothing And val.Contains(strFind) Then
                                txt.TextString = val.Replace(strFind, strReplace)
                                txt.RecordGraphicsModified(True)
                                tbl.Rows.Add(txt.TextString, val, "DBText", dwgName, hand, wksp, locX, locY, locZ)
                            End If

                        Case "MTEXT"
                            Dim mtxt As MText = CType(tr.GetObject(objId, OpenMode.ForWrite), MText),
                                    wksp As String = mtxt.BlockName.ToString,
                                    hand As String = mtxt.Handle.ToString,
                                    val As String = mtxt.Contents.ToString,
                                    locX As String = mtxt.Location.X.ToString,
                                    locY As String = mtxt.Location.Y.ToString,
                                    locZ As String = mtxt.Location.Z.ToString
                            If hand <> Nothing And val <> Nothing And val.Contains(strFind) = True Then
                                mtxt.Contents = val.Replace(strFind, strReplace)
                                mtxt.RecordGraphicsModified(True)
                                tbl.Rows.Add(mtxt.Contents, val, "MText", dwgName, hand, wksp, locX, locY, locZ)
                            End If

                        Case "Attribute"
                            Dim att As AttributeReference = CType(tr.GetObject(objId, OpenMode.ForWrite), AttributeReference),
                                    wksp As String = att.BlockName.ToString,
                                    hand As String = att.Handle.ToString,
                                    val As String = att.TextString,
                                    locX As String = att.Position.X.ToString,
                                    locY As String = att.Position.Y.ToString,
                                    locZ As String = att.Position.Z.ToString
                            If hand <> Nothing And val <> Nothing And hand <> Nothing And val.Contains(strFind) = True Then
                                att.TextString = val.Replace(strFind, strReplace)
                                att.RecordGraphicsModified(True)
                                tbl.Rows.Add(att.TextString, val, "Attribute", dwgName, hand, wksp, locX, locY, locZ)
                            End If
                    End Select
                Next
                tr.Commit()
                tr.Dispose()
            End Using
        End Using
    End Sub


Wayne Perciful
Founder | Perciful Consulting LLC
Perciful Consulting

0 Likes
Accepted solutions (1)
1,818 Views
4 Replies
Replies (4)
Message 2 of 5

_gile
Consultant
Consultant

Hi,

 

In your second method, after having commited the transaction, you have to save the changes in the database:

 

 

db.SaveAs(fn, DwgVersion.Current)

Another thing, you won't get any AttributeReference directly in the model space. you have to get the block references first, and iterate through their AttributeCollection.

 



Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 3 of 5

_gile
Consultant
Consultant
Accepted solution

Here's a quick example (C# but easily convertible).

I'd rather use  a return value and arguments because I do not know where 'tbl', 'strFind' and 'strReplace' are from.

 

        public List<string[]> FindReplace(string fileName, string find, string replace)
        {
            using (Database db = new Database(false, true))
            {
                try
                {
                    db.ReadDwgFile(fileName, FileOpenMode.OpenForReadAndAllShare, false, null);
                }
                catch { return null; }
                var log = new List<string[]>();
                var textClass = RXObject.GetClass(typeof(DBText));
                var mtextClass = RXObject.GetClass(typeof(MText));
                var blockRefClass = RXObject.GetClass(typeof(BlockReference));
                using (var tr = db.TransactionManager.StartTransaction())
                {
                    var modelSpace = (BlockTableRecord)tr.GetObject(
                        SymbolUtilityServices.GetBlockModelSpaceId(db), OpenMode.ForRead);
                    foreach (ObjectId id in modelSpace)
                    {
                        if (id.ObjectClass.IsDerivedFrom(textClass))
                        {
                            var text = (DBText)tr.GetObject(id, OpenMode.ForWrite);
                            var str = text.TextString;
                            var pt = text.Position;
                            text.TextString = str.Replace(find, replace);
                            log.Add(new[] {
                                text.TextString,
                                str,
                                "DBText",
                                Path.GetFileName(fileName),
                                text.Handle.ToString(),
                                text.BlockName,
                                pt.X.ToString(),
                                pt.Y.ToString(),
                                pt.Z.ToString() });
continue; } if (id.ObjectClass.IsDerivedFrom(mtextClass)) { var text = (MText)tr.GetObject(id, OpenMode.ForWrite); var str = text.Contents; var pt = text.Location; text.Contents = str.Replace(find, replace); log.Add(new[] { text.Contents, str, "MText", Path.GetFileName(fileName), text.Handle.ToString(), text.BlockName, pt.X.ToString(), pt.Y.ToString(), pt.Z.ToString() });
continue; } if (id.ObjectClass.IsDerivedFrom(blockRefClass)) { var blockRef = (BlockReference)tr.GetObject(id, OpenMode.ForRead); foreach (ObjectId attId in blockRef.AttributeCollection) { var attRef = (AttributeReference)tr.GetObject(attId, OpenMode.ForWrite); var str = attRef.TextString; var pt = attRef.Position; attRef.TextString = str.Replace(find, replace); log.Add(new[] { attRef.TextString, str, "AttributeReference", Path.GetFileName(fileName), attRef.Handle.ToString(), attRef.BlockName, pt.X.ToString(), pt.Y.ToString(), pt.Z.ToString() }); } } } tr.Commit(); } db.SaveAs(fileName, DwgVersion.Current); return log; } }


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

Message 4 of 5

WPerciful
Advocate
Advocate

I've added that line of code, but it results in a 'eFileError'.  I'm on my office computer, but my app is written on my personal laptop which doesn't have internet access at the moment.  So I retyped the rest of my code so that you can see it.

 

tbl is set on form load, and the code works.  It's just so I can have a log of the changes. 

 

 

Dim fdb As New System.Windows.Forms.FolderBrowserDialog,
        strFind As string = txtFind.Text,
        strReplace As string = txtReplace.Text

If (fdb.ShowDialog = Windows.Forms.DialogResult.Ok) Then
        Dim FileEntries As String() = IO.Directory.GetFiles(fdb.SelectedPath, "*.dwg")
        For Each dwg As String In FileEntries
                test(dwg)
        Next
End If
dgv.DataSource = tbl    


Wayne Perciful
Founder | Perciful Consulting LLC
Perciful Consulting

0 Likes
Message 5 of 5

WPerciful
Advocate
Advocate

Merci beaucoup!!!!!



Wayne Perciful
Founder | Perciful Consulting LLC
Perciful Consulting

0 Likes