.NET
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Finding & Replacing Mtext in a Block using VB.net?

31 REPLIES 31
SOLVED
Reply
Message 1 of 32
kennedyb
3261 Views, 31 Replies

Finding & Replacing Mtext in a Block using VB.net?

Hi everyone,

 

I've been trying to find help on replacing Mtext in a drawing border of mine. The drawing border is a block that has constant attributes that I have a vb.net dll that can edit the constant attributes.

 

I'm trying to add this to that dll, I would like this to work in such a way as to not have the user involved. My thought was to have the code executed when the form was loaded to edit the values in the titleblock. The code would look to see if the Mtext existed in the border and if so replace it with the correct Mtext. If the correct Mtext is there it would exit the Sub.

 

I'm have a hard time figuring out how to use the Transaction concept. I've tried to modify an exisitng function in the VB.net dll to do this change.

 

As you can see in this example code, I'm not very good at figuring out how to modify it to my needs. I'm still not sure how some of these "BIG PICTURE" concepts work?

 

Do I need one function to read and another function to write? Do I need a Sub to strat to function(s)?  I understand most of  form code.

 

Any pointers in the correct direction would be appreciated....

 

PublicSharedFunction ReadMtextFromBTR(ByVal strName AsMText) AsMTextDim MtxtList AsList(Of Text.StringBuilder)

 

Dim oDwg AsDocument = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument

 

Dim oDB As DatabaseServices.Database= oDwg.Database

 

Dim oTransMgr As DatabaseServices.TransactionManager= oDB.TransactionManager

 

Dim oTrans As DatabaseServices.Transaction= oTransMgr.StartTransaction

 

UsingoTrans

 

Dim oDatabaseObject AsDBObject = oDB.BlockTableId.GetObject(DatabaseServices.OpenMode.ForRead)

 

Dim oBlockTable As DatabaseServices.BlockTable = DirectCast(oDatabaseObject, BlockTable)

 

Dim oBTRE As DatabaseServices.SymbolTableEnumerator= oBlockTable.GetEnumerator

 

WhileoBTRE.MoveNext

 

Dim oDBObject AsDBObject = oBTRE.Current.GetObject(DatabaseServices.OpenMode.ForRead)

 

Dim oBTR As DatabaseServices.BlockTableRecord = DirectCast(oDBObject, BlockTableRecord)

 

If oBTR.Name = strName.Text ThenForEach oObjectID AsObjectIdInoBTR

 

Dim oEnt AsDBObject = oTrans.GetObject(oObjectID, OpenMode.ForRead)

 

'If oEnt.GetType.ToString = "Autodesk.AutoCAD.DatabaseServices.AttributeDefinition" ThenIfTypeOf oEnt Is Autodesk.AutoCAD.DatabaseServices.MTextThen

oEnt.UpgradeOpen()

If oEnt.ToString >= ("FirstEnergy ") ThenSelectCaseCase"FirstEnergy GENERATION CORP."ReturnstrName

 

Case"FirstEnergy _"

GENERATION, LLC"

Return2

 

Case ElseThrowNewException("The border did not match any of the defined types.")

 

EndSelectEndIfEndIfNextEndIfEndWhile'oTrans.Commit()EndUsing

oTrans.Dispose()

oTransMgr.Dispose()

oDB.Dispose()

Return MtxtList

 

 

 

 

 

31 REPLIES 31
Message 2 of 32
StephenPreston
in reply to: kennedyb

So your main question is how to better understand how to better understand and use the .NET API? If so, I recommend you work through the .NET Training Labs we have posted here - www.autodesk.com/developautocad (under the 'Learning' section. Note that there is also a 'DevTV' link to the left of the links to the material that includes a set of videos talking therough each of the training labs. If you're very new to programming, then the 'My First Plug-in' tutorial on the same page may be helpful too.

 

BTW In your code below, you seem to have commented out the 'trans.Commit()' line, which means your transaction will be aborted when it is Disposed and any changes you made to the drawing since you started the transaction will be rolled back. You should also look in the tutorials I mention how you can use For Each...Next instead of GetEnumerator/MoveNext - its a lot simpler.

 

Cheers,

Stephen Preston
Autodesk Developer Network
Message 3 of 32
mzakiralam
in reply to: kennedyb

To get all the mtext in a block, you can use selection filter. Selection filter will accumulate all entity according to your selection. Below I have create a code snip which will gather all the mtext in the model space. Please see below.

 Public Shared Function GetMTextBTR(acEd As Editor) As ObjectIdCollection
        Dim tvs(0) As TypedValue
        tvs.SetValue(New TypedValue(DxfCode.Start, "MTEXT"), 0)
        Dim sf As New SelectionFilter(tvs)
        Dim psr As PromptSelectionResult = acEd.SelectAll(sf)
        If psr.Status = PromptStatus.OK Then
            Return New ObjectIdCollection(psr.Value.GetObjectIds())
        Else
            Return New ObjectIdCollection()
        End If
    End Function
    <CommandMethod("tst")> Public Sub TESTMtext()
        Dim doc As Document = Application.DocumentManager.MdiActiveDocument
        Dim db As Database = doc.Database
        Dim ed As Editor = doc.Editor
        Using tx As Transaction = db.TransactionManager.StartTransaction()
            Dim bt As BlockTable = tx.GetObject(db.BlockTableId, OpenMode.ForRead)
            Dim ms As BlockTableRecord = tx.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead)
            Dim objIdColl As ObjectIdCollection = GetMTextBTR(ed)
            For Each objId As ObjectId In objIdColl
                'DO SOMETHING
            Next
            tx.Commit()
        End Using
    End Sub

 

Message 4 of 32
kennedyb
in reply to: mzakiralam

mzakiralam

 

Thank you for the Code snippet.

In your example code, I don't have a grasp on what I should be placing for code in the "DO Something" area.

 

I've tried to use a "If statement" to determine if the particular Mtext is what I want to change. I can't seem to unerstand how to do this part. (see below)

 

 

 

The "Lightbulb" is starting to glow Smiley LOL I see the function piece in the command sub.

 

 

For some reason your supplied code wasn't liked "as is". I had to change it to this

 

Using tx AsTransaction= db.TransactionManager.StartTransaction()

 

Dim bt AsBlockTable = CType(tx.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable)

 

Dim ms AsBlockTableRecord = CType(tx.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead), BlockTableRecord)

 

Dim objIdColl AsObjectIdCollection = FirstEnergy.AutoCADFunctions.GetMTextBTR(ed)

 

ForEach objId AsObjectIdIn objIdColl 'DO SOMETHING Next If objId.GetObject(ms.Equals("TEST") Then

MsgBox(

"you found it")

 

Else

MsgBox(

"that's not it")

 

EndIfNext 

Message 5 of 32
mzakiralam
in reply to: kennedyb

I was not sure what you need to do. This is why after  getting the objectId , I have written "Do Something" Smiley Wink. Is it now working for you?

 

if not please see my below code and further explanation. Suppose I have created three MTEXT in my drawing and MTEXT are test1, test2 and test3. If test1 is found it will give a message like "found test1" and so on for others. Please see below code

 

 <CommandMethod("tst")> Public Sub TESTMtext()
        Dim doc As Document = Application.DocumentManager.MdiActiveDocument
        Dim db As Database = doc.Database
        Dim ed As Editor = doc.Editor
        Using tx As Transaction = db.TransactionManager.StartTransaction()
            Dim bt As BlockTable = tx.GetObject(db.BlockTableId, OpenMode.ForRead)
            Dim ms As BlockTableRecord = tx.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead)
            Dim objIdColl As ObjectIdCollection = GetMTextBTR(ed)
            For Each objId As ObjectId In objIdColl
                'get the Mtext from objectID
                Dim mtxt As MText = tx.GetObject(objId, OpenMode.ForWrite)
                'check mtext content
                If mtxt.Contents = "test1" Then
                    MsgBox("found test1")
                ElseIf mtxt.Contents = "test2" Then
                    MsgBox("found test2")
                ElseIf mtxt.Contents = "test3" Then
                    MsgBox("found test3")
                End If
            Next
            tx.Commit()
        End Using
    End Sub

 

Message 6 of 32
kennedyb
in reply to: mzakiralam

No,

 

I'm still gropeing along trying to figure out what to plug into the "Do Something". I kinda understand the Function you supplied. It is collecting object Ids that are Mtext and adding them to the editor? Or is the Function looking for something specifically called "MTEXT"?

 

What I want to do is Find this Mtext ("FirstEnergy GENERATION CORP.") and replace with ("FirstEnergy GENERATION, LLC).

 

There is only one (1) of these Mtext strings in the block reference.

Message 7 of 32
mzakiralam
in reply to: kennedyb

My function will collect all MText entities in the model space. It is not related with something Special. It will only collect objectId which DBObject are MText. After getting objectId, you can get MText . Then you can implement your purpose . According to your Need I have modified above code. Please see below. I did not try this code. But it should work

 

<CommandMethod("tst")> Public Sub TESTMtext()
        Dim doc As Document = Application.DocumentManager.MdiActiveDocument
        Dim db As Database = doc.Database
        Dim ed As Editor = doc.Editor
        Using tx As Transaction = db.TransactionManager.StartTransaction()
            Dim bt As BlockTable = tx.GetObject(db.BlockTableId, OpenMode.ForRead)
            Dim ms As BlockTableRecord = tx.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead)
            Dim objIdColl As ObjectIdCollection = GetMTextBTR(ed)
            For Each objId As ObjectId In objIdColl
                'get the Mtext from objectID
                Dim mtxt As MText = tx.GetObject(objId, OpenMode.ForWrite)
                'check mtext content
                If mtxt.Contents = "FirstEnergy GENERATION CORP." Then
                   mtxt.contents = "FirstEnergy GENERATION, LLC"
                End If
            Next
            tx.Commit()
        End Using
    End Sub

 

Message 8 of 32
kennedyb
in reply to: mzakiralam

OK!

 

 

Bulb getting a little brighter Smiley Embarassed So I should be able to find said string, then replace it with new string and commit?

 

SO, if I figure out the FIND replace I can call this "Command" when the FORM loads? It will automatically search and replace if necessary?

Message 9 of 32
mzakiralam
in reply to: kennedyb

To understand properly of that function, you can have a look in below link.

http://exchange.autodesk.com/autocad/enu/online-help/browse#WS1a9193826455f5ff2566ffd511ff6f8c7ca-40...
Message 10 of 32
mzakiralam
in reply to: kennedyb

In that case you do not Need to call this command. Just put that Sub routine in the form loading Event.
Message 11 of 32
kennedyb
in reply to: mzakiralam

Well, still stumbling.

 

I've tried to shorten what Mtext to look for (see code) but nothing is happening?

 

I noticed in the code you've supplied that there isn't anything that is qualifying the MText to look for, like inside a Blockreference? Does the function care? Can it see Mtext in the Block reference?

 

Also, I did a properties on an example Mtext = " CORP." and the properties show a bunch of formating info. Is the formating info ignored when the Function/ Sub is executed?

 

        Public Sub TESTMtext()

            Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor



            Using tx As Transaction = db.TransactionManager.StartTransaction()

                Dim bt As BlockTable = tx.GetObject(db.BlockTableId, OpenMode.ForRead)
                Dim ms As BlockTableRecord = tx.GetObject(bt(BlockTableRecord.ModelSpace), OpenMode.ForRead)
                Dim objIdColl As ObjectIdCollection = FirstEnergy.AutoCADFunctions.GetMTextBTR(ed)

                For Each objId As ObjectId In objIdColl
                    'get the Mtext from objectID
                    Dim mtxt As MText = tx.GetObject(objId, OpenMode.ForWrite)
                    'check mtext content
                    If mtxt.Contents = (" CORP.") Then
                        mtxt.Contents = (", LLC")
                    End If
                Next


                tx.Commit()
            End Using

 

 

Message 12 of 32
mzakiralam
in reply to: kennedyb

with this current function , it will not look MText in any BlockReference. I will try to accumulate objectId of MText if it is in ModelSpace. If your MText are in a block reference then enter into that block reference and apply that function.
Message 13 of 32
jeff
in reply to: mzakiralam

I really do not know how you could use that function for your purposes or use Editor.SelectAll on  BlockTableRecord without a layout.

 

Here is a thread where Norman helps someone and shows how to use a selection filter to get all BlockReferences then look inside the blocks.

http://forums.autodesk.com/t5/NET/Blocks-attributes-and-selection-sets/m-p/4331537/highlight/true

 

 

There are much better ways to streamline this and make it reusable, but just for learning purposes here is another approach.

 

  1. At the top is a string which would be the name of the block.
  2. Both methods check to see if the drawing contains the block.
  3. Instead of opening every object to check if it is the correct type there is a property you can check from the ObjectId to save time.
  4. Since you mention constant attributes those will be contained in the BlockTableRecord only and not attached to the BlockReferences
  5. Mtext.Text returns a string with formatting removed & Mtext.Contents will contain formatting

So making part of mtext bold and and changing the last bit to red the attached drawing will print

Mtext.Contents = THIS IS {\fArial|b1|i0|c0|p34;MTEXT \C1;FORMATTED}
Mtext.Text= THIS IS MTEXT FORMATTED

 

Have not written VB for a long time, Sorry.

 

 

   Dim blockName As String = "BlockName"
        <CommandMethod("LooKForMtext")> _
        Public Sub LooKForMtext() 
            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor

            Using trx As Transaction = db.TransactionManager.StartTransaction()

                Dim blockTbl As BlockTable = trx.GetObject(db.BlockTableId, OpenMode.ForRead)

                If Not blockTbl.Has(blockName) Then
                    ed.WriteMessage(Environment.NewLine & "Block not in drawing")
                    Return
                End If

                Dim block As BlockTableRecord = trx.GetObject(blockTbl(blockName), OpenMode.ForRead)

                Dim mtxtClassptr As IntPtr = RXClass.GetClass(GetType(MText)).UnmanagedObject

                For Each entId As ObjectId In block
                    If entId.ObjectClass.UnmanagedObject = mtxtClassptr Then
                        Dim mtxt As MText = trx.GetObject(entId, OpenMode.ForRead)
                        ed.WriteMessage(Environment.NewLine & mtxt.Contents)
                        ed.WriteMessage(Environment.NewLine & mtxt.Text)
                    End If
                Next

            End Using

        End Sub

        <CommandMethod("LooKForConstantAttributes")> _
        Public Sub LooKForConstantAttributes() ' This method can have any name
            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor

            Using trx As Transaction = db.TransactionManager.StartTransaction()

                Dim blockTbl As BlockTable = trx.GetObject(db.BlockTableId, OpenMode.ForRead)

                If Not blockTbl.Has(blockName) Then
                    ed.WriteMessage(Environment.NewLine & "Block not in drawing")
                    Return
                End If

                Dim block As BlockTableRecord = trx.GetObject(blockTbl(blockName), OpenMode.ForRead)

                If Not block.HasAttributeDefinitions Then
                    ed.WriteMessage(Environment.NewLine & "No attributes in block")
                    Return
                End If


                Dim attDefClassptr As IntPtr = RXClass.GetClass(GetType(AttributeDefinition)).UnmanagedObject

                For Each entId As ObjectId In block
                    If entId.ObjectClass.UnmanagedObject = attDefClassptr Then
                        Dim attDef As AttributeDefinition = trx.GetObject(entId, OpenMode.ForRead)
                        ed.WriteMessage(Environment.NewLine & attDef.Constant)
                        ed.WriteMessage(Environment.NewLine & attDef.Tag)
                        If attDef.IsMTextAttributeDefinition Then
                            ed.WriteMessage(Environment.NewLine & attDef.MTextAttributeDefinition.Contents)
                        Else
                            ed.WriteMessage(Environment.NewLine & attDef.TextString)
                        End If

                    End If

                Next

            End Using

        End Sub



    End Class

 

 

You can also find your answers @ TheSwamp
Message 14 of 32
jeff
in reply to: jeff

Forgot to commit transaction and should not hard code values inside fuction but this will get you started

 

        <CommandMethod("LooKForMtext")> _
        Public Sub LooKForMtext() ' This method can have any name
            Dim doc As Document = Application.DocumentManager.MdiActiveDocument
            Dim db As Database = doc.Database
            Dim ed As Editor = doc.Editor

            Using trx As Transaction = doc.TransactionManager.StartTransaction()

                Dim blockTbl As BlockTable = trx.GetObject(db.BlockTableId, OpenMode.ForRead)

                If Not blockTbl.Has(blockName) Then
                    ed.WriteMessage(Environment.NewLine & "Block not in drawing")
                    Return
                End If

                Dim block As BlockTableRecord = trx.GetObject(blockTbl(blockName), OpenMode.ForRead)

                Dim mtxtClassptr As IntPtr = RXClass.GetClass(GetType(MText)).UnmanagedObject

                For Each entId As ObjectId In block
                    If entId.ObjectClass.UnmanagedObject = mtxtClassptr Then
                        Dim mtxt As MText = trx.GetObject(entId, OpenMode.ForRead)
                        If mtxt.Text.IndexOf("FirstEnergy GENERATION CORP", StringComparison.InvariantCultureIgnoreCase) >= 0 Then
                            mtxt.UpgradeOpen()
                            mtxt.Contents = mtxt.Contents.Replace("CORP", "LLC")
                        End If
                    End If
                Next
                trx.Commit()
            End Using
            ed.Regen()
        End Sub

 

You can also find your answers @ TheSwamp
Message 15 of 32
kennedyb
in reply to: jeff

Thank you!!!! Jeff,

mzakiralam, & Stephen

 


I've learned more in the past few hours than all the rest of the time I've
tried to figure this out on my own, on my own I've spent weeks looking at
example code.
The code sorta made sense, but the context is what I believe was
missing. Not knowing how to apply it is very frustrating.

Message 16 of 32
StephenPreston
in reply to: kennedyb

Please mark Jeff's answer as an Accepted Solution (and give him Kudos) if his code answered your question :-).

 

 

Cheers,

Stephen Preston
Autodesk Developer Network
Message 17 of 32
kennedyb
in reply to: jeff

I'm still struggling,

 

I can't seem to grab the Block "that is there" to look for the Mtext. Tried to dim the TypedValue as a block but doesn't seem to effect the code?

 

Aslo tried the

Dim

blockname As String = "F-size" <---this is one of the Blocks that could be in the drawing.

 

It always says the block isn't there?

 

I don't understand what I'm missing?

 

 

 

Message 18 of 32
mzakiralam
in reply to: kennedyb

Can you send your drawing? I am sorry that yesterday , I did not understand your requirement fully.Therefore I only mention about MText in the model space block. Do you want to change some text which is as the attribute of a block reference in the drawing?

Message 19 of 32
kennedyb
in reply to: mzakiralam

 
mzakiralam,
 
 
 
 


I'm not trying to replace Mtext in an attribute, the Mtext is just inside the "titleblock" BLOCK. I've attached one of the template files that has the Mtext I'm trying to replace.

 
Message 20 of 32
mzakiralam
in reply to: kennedyb

Did you attach the file? I can not see any attachment.

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk DevCon in Munich May 28-29th


Autodesk Design & Make Report

”Boost