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
Solved! Go to Solution.
Solved by kennedyb. Go to Solution.
I don't know why but I'm having issues with attaching the file.
Here is my next attempt
Hi,
Try this:
Imports Autodesk.AutoCAD.ApplicationServices Imports Autodesk.AutoCAD.DatabaseServices Imports Autodesk.AutoCAD.EditorInput Imports Autodesk.AutoCAD.Runtime <Assembly: CommandClass(GetType(CommandMethods))> Public Class CommandMethods <CommandMethod("Test", CommandFlags.Modal)> _ Public Sub Test() Dim doc As Document = Application.DocumentManager.MdiActiveDocument Dim db As Database = doc.Database Dim ed As Editor = doc.Editor Dim mtextClass As RXClass = RXClass.GetClass(GetType(MText)) Using tr As Transaction = db.TransactionManager.StartTransaction() Dim bt As BlockTable = DirectCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable) If Not bt.Has("A-Size") Then Application.ShowAlertDialog("Block 'A-Size' not found.") Return End If Dim btr As BlockTableRecord = DirectCast(tr.GetObject(bt("A-Size"), OpenMode.ForRead), BlockTableRecord) For Each id As ObjectId In btr If id.ObjectClass = mtextClass Then Dim mtext As MText = DirectCast(tr.GetObject(id, OpenMode.ForRead), MText) If mtext.Contents.Contains(" CORP.") Then mtext.UpgradeOpen() mtext.Contents = mtext.Contents.Replace(" CORP.", ", LLC") End If End If Next tr.Commit() End Using ed.Regen() End Sub End Class
_gile
Your code works as a typed command. Im trying to figure out how to have this automatically happen when the Editor Form is loaded. The trick here is some Blocks will already be correct ,(i.e. LLC). Also this .dll is used to create new drawings, so the new drawing will be using a template file that has the correct Mtext in it (LLC).
I had this TitleBlock editor created with ALOT of help from another person. This person is no longer able to assit me with code changes since he's no longer with the company. This Post has helped me EMENSLY in understanding these concepts.
I made some changes to the code to acomodate multiple title block names, (see code below). I've tried to add this code the the Public New Sub that's part of the Form Code. I'm not sure were this belongs? In a previous post I was told to add this code to the Form Load Event. I was in the Events portion of the VB IDE trying to figure out how to do that?
Also, the below code ( in this Sub) keeps giving me a eLock error.
Private _TitleBlockName As String = FirstEnergy.AutoCADFunctions.GetTitleBlockName Public Sub New() ' This call is required by the designer. InitializeComponent() ' Add any initialization after the InitializeComponent() call. Dim doc As Document = ApplicationServices.Application.DocumentManager.MdiActiveDocument Dim db As Database = doc.Database Dim ed As Editor = doc.Editor Dim mtextClass As RXClass = RXClass.GetClass(GetType(MText)) Dim Sze As String = _TitleBlockName Using tr As Transaction = db.TransactionManager.StartTransaction() Dim bt As BlockTable = DirectCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable) If Not bt.Has(Sze) Then ''Application.ShowAlertDialog("Block" & Sze.ToString & "Not Found") Return End If Dim btr As BlockTableRecord = DirectCast(tr.GetObject(bt(Sze), OpenMode.ForRead), BlockTableRecord) For Each id As ObjectId In btr If id.ObjectClass = mtextClass Then Dim mtext As MText = DirectCast(tr.GetObject(id, OpenMode.ForRead), MText) If mtext.Contents.Contains(" CORP.") Then mtext.UpgradeOpen() mtext.Contents = mtext.Contents.Replace(" CORP.", ", LLC") End If End If Next tr.Commit() End Using ed.Regen() m_IsLoadingControls = True '// Init the combo boxes cboSCALE1.Items.AddRange(FirstEnergyEditor.Constants.DrawingScales()) cboSCALE1.SelectedIndex = 0 cboDWGTYPE.Items.AddRange(FirstEnergyEditor.Constants.DrawingTypes) cboPLANTORVENDOR.Items.AddRange(FirstEnergyEditor.Constants.PlantOrVendorTypes) cboDRAWINGSTATUS.Items.AddRange(FirstEnergyEditor.Constants.DrawingStatusTypes) cboGENTRANS.Items.AddRange(FirstEnergyEditor.Constants.GenTranTypes) LblOpenRev.Show() End Sub
Hi,
First you'd rather write a separate Sub with one argument (the block name) so that you can call from any other place (a command method, a control event handler, an initialization method).
If you want to execute some code at AutoCAD startup, create a class which implements the IExtensionApplication interface and call the sub from the Initialize method (you must implement this method).
The way to execute a sub in each (already or newly) created document is to add an event handler for the DocumentManager.DocumentCreated event.
Make a serch with IExtensionApplication.
_gile
I've tried to figure out what your tell me to do. I have your code as a Sub, I've tried to place it in different locations (Namespaces) I have.
I can't seem to figure out how to tie it to the loading of form to edit the titleblock?
If I undersand your latest post, I need to create a Sub that is calling the Sub
<CommandMethod("LookForLLC")> _PublicSub LLC()? I've tried that with no success.
I see the IExtensionApplication in the object browser. But I think we may be talking about different things? All I want this code to do is change " CORP." to ", LLC" if the person opens a drawing for edit that was previously made with an older template.
As I stated earlier, the code works perfectly as typed command.
Hi,
As you want to change mtext while document is activated so you can check the below code. in Public sub Initialize method you can see that I have add handler for ReplaceMtextinTitleBlock. This handler will be activated during your dll loading. ReplaceMtextinTitleBlock sub will be called when new document is created in Autocad editor. gile has already suggested this kind of method. Now put your code in Public Sub ReplaceMtextinTitleBlock routine and try to run the code.
Public Class MyTest Implements Autodesk.AutoCAD.Runtime.IExtensionApplication Public Sub Initialize() Implements Autodesk.AutoCAD.Runtime.IExtensionApplication.Initialize Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor ed.WriteMessage("DLL loading and document created handler added") AddHandler Application.DocumentManager.DocumentCreated, AddressOf ReplaceMtextinTitleBlock End Sub Public Sub Terminate() Implements Autodesk.AutoCAD.Runtime.IExtensionApplication.Terminate 'do not need to put any code here End Sub Public Sub ReplaceMtextinTitleBlock(ByVal senderObj As Object, ByVal docColDocActEvtArgs As DocumentCollectionEventArgs) 'put your mtext replacing code End Sub End Class
mzakiralam
I must be Dumb as a sack of dirty diapers 😞
I looked your code over and found similar code in the "MyPlugin" namespace. I added the handlers to the same location as the other handlers.
I added the Sub ReplaceMtextinTitleBlock (with minor changes to the Sze Dim) to the same namespace. All seems syntax correct.
I still don't know how to get this Sub to "Fire" when the Form frmTitleBlockEditor is loaded? Attached is the MyPlugin code.
Imports System Imports Autodesk.AutoCAD Imports Autodesk.AutoCAD.Runtime Imports Autodesk.AutoCAD.ApplicationServices Imports Autodesk.AutoCAD.DatabaseServices Imports Autodesk.AutoCAD.EditorInput ' This line is not mandatory, but improves loading performances <Assembly: ExtensionApplication(GetType(TitleBlockEditorNET.MyPlugin))> Namespace TitleBlockEditorNET ' This class is instantiated by AutoCAD once and kept alive for the ' duration of the session. If you don't do any one time initialization ' then you should remove this class. Public Class MyPlugin Implements IExtensionApplication Dim WithEvents AcadAPP As Application Dim WithEvents AcadDWG As Document Dim WithEvents AcadDM As DocumentCollection = Application.DocumentManager() Private _sIdleHandlerOwner As String Private _eDocumentLockMode As DocumentLockMode Dim _bTitleBlockDoubleClicked As Boolean Public Sub Initialize() Implements IExtensionApplication.Initialize 'Declarations '============ Dim oDwg As Document = Application.DocumentManager.MdiActiveDocument Dim oDM As DocumentCollection = Application.DocumentManager() Dim oDB As Database = oDwg.Database Dim oEd As Editor = oDwg.Editor Dim ed As Editor = Application.DocumentManager.MdiActiveDocument.Editor ed.WriteMessage("DLL loading and document created handler added") ''AddHandler Application.DocumentManager.DocumentCreated, AddressOf ReplaceMtextinTitleBlock '========= 'Turn on application-level event handlers AddHandler Application.DocumentManager.DocumentCreated, AddressOf AcadDocumentCreated AddHandler Application.DocumentManager.DocumentCreated, AddressOf ReplaceMtextinTitleBlock AddHandler Application.DocumentManager.DocumentActivated, AddressOf AcadDocumentActivated ''AddHandler Application.DocumentManager.DocumentCreated, AddressOf ReplaceMtextinTitleBlock() AddHandler Application.BeginDoubleClick, AddressOf AcadBeginDoubleClick 'AddHandler Application.Idle, AddressOf AcadIdle 'Turn on document-level event handlers for current drawing AddHandler oDM.DocumentLockModeChanged, AddressOf AcadDocumentLockModeChanged AddHandler oDwg.CommandEnded, AddressOf AcadDocumentCommandEnded AddHandler oDwg.CommandCancelled, AddressOf AcadDocumentCommandCanceled AddHandler oDwg.EndDwgOpen, AddressOf AcadEndDwgOpen 'AddHandler oEd.SelectionAdded, AddressOf AcadSelectionAdded 'Ensure FirstEnergy UI elements are loaded 'Call modAppCommands.FECUI() Call modAppCommands.FECONTEXT() End Sub Public Sub Terminate() Implements IExtensionApplication.Terminate ' Do plug-in application clean up here End Sub Private Sub AcadDocumentCreated(ByVal sender As Object, ByVal e As Autodesk.AutoCAD.ApplicationServices.DocumentCollectionEventArgs) 'Declarations '============ Dim oDwg As Document Dim oDB As Database = Application.DocumentManager.MdiActiveDocument.Database Dim oEd As Editor Dim oDM As DocumentCollection = Application.DocumentManager() 'Begin Sub '========= oDwg = Application.DocumentManager.MdiActiveDocument If oDwg.IsReadOnly Then MsgBox("Drawing is read-only.") Return End If oEd = oDwg.Editor 'Turn on event handlers AcadDWG = e.Document AddHandler oDM.DocumentLockModeChanged, AddressOf AcadDocumentLockModeChanged AddHandler oDwg.CommandEnded, AddressOf AcadDocumentCommandEnded AddHandler oDwg.CommandCancelled, AddressOf AcadDocumentCommandCanceled AddHandler oDwg.EndDwgOpen, AddressOf AcadEndDwgOpen 'AddHandler oEd.SelectionAdded, AddressOf AcadSelectionAdded 'Ensure FirstEnergy UI elements are loaded 'Call modAppCommands.FECUI() 'Call modAppCommands.FECONTEXT() End Sub Sub AcadDocumentCommandEnded(ByVal sender As Object, ByVal e As CommandEventArgs) 'Debug.Print(e.GlobalCommandName.ToString) 'If g_bTitleBlockDoubleClicked Then ' Try ' Dim frm As New frmTitleBlockEditor ' Autodesk.AutoCAD.ApplicationServices.Application.ShowModelessDialog(frm) ' Catch ex As Autodesk.AutoCAD.Runtime.Exception ' MsgBox(ex.Message.ToString) ' End Try 'End If End Sub Sub AcadDocumentCommandCanceled() Debug.Print("Canceled") End Sub Public Sub ReplaceMtextinTitleBlock(ByVal senderObj As Object, ByVal docColDocActEvtArgs As DocumentCollectionEventArgs) 'put your mtext replacing code Dim doc As Document = ApplicationServices.Application.DocumentManager.MdiActiveDocument Dim db As Database = doc.Database Dim Ed As Editor = doc.Editor Dim mtextClass As RXClass = RXClass.GetClass(GetType(MText)) Dim Sze As String = FirstEnergy.AutoCADFunctions.GetTitleBlockName Using tr As Transaction = db.TransactionManager.StartTransaction() Dim bt As BlockTable = DirectCast(tr.GetObject(db.BlockTableId, OpenMode.ForRead), BlockTable) If Not bt.Has(Sze) Then ''Application.ShowAlertDialog("Block" & Sze.ToString & "Not Found") Return End If Dim btr As BlockTableRecord = DirectCast(tr.GetObject(bt(Sze), OpenMode.ForRead), BlockTableRecord) For Each id As ObjectId In btr If id.ObjectClass = mtextClass Then Dim mtext As MText = DirectCast(tr.GetObject(id, OpenMode.ForRead), MText) If mtext.Contents.Contains(" CORP.") Then mtext.UpgradeOpen() mtext.Contents = mtext.Contents.Replace(" CORP.", ", LLC") End If End If Next tr.Commit() End Using Ed.Regen() End Sub Sub AcadBeginDoubleClick(ByVal sender As Object, ByVal e As Autodesk.AutoCAD.ApplicationServices.BeginDoubleClickEventArgs) Dim oDwg As Document = Application.DocumentManager.MdiActiveDocument Dim oEd As Editor = oDwg.Editor Dim oPSR As PromptSelectionResult = oEd.SelectImplied Dim oSS As SelectionSet = oPSR.Value Dim oArrayOIDs() As ObjectId Dim oEnt As Entity Dim oBlkRef As BlockReference If oSS Is Nothing Then Return End If Dim tr As Transaction = oDwg.TransactionManager.StartTransaction Using tr 'Process selection set oArrayOIDs = oSS.GetObjectIds() For Each oOID In oArrayOIDs oEnt = oOID.GetObject(OpenMode.ForRead) If TypeOf oEnt Is BlockReference Then oBlkRef = CType(oEnt, BlockReference) Select Case oBlkRef.Name Case "A-Size" _sIdleHandlerOwner = "AcadBeginDoubleClick" Case "B-Size" _sIdleHandlerOwner = "AcadBeginDoubleClick" Case "C-Size" _sIdleHandlerOwner = "AcadBeginDoubleClick" Case "D-Size" _sIdleHandlerOwner = "AcadBeginDoubleClick" Case "E-Size" _sIdleHandlerOwner = "AcadBeginDoubleClick" Case "F-Size" _sIdleHandlerOwner = "AcadBeginDoubleClick" Case "G-Size" _sIdleHandlerOwner = "AcadBeginDoubleClick" Case "X-Size" _sIdleHandlerOwner = "AcadBeginDoubleClick" Case Else _sIdleHandlerOwner = "AcadBeginDoubleClick" End Select Debug.Print(oBlkRef.Name) End If Next oOID End Using End Sub Sub AcadIdle(ByVal sender As Object, ByVal e As System.EventArgs) Debug.Print("IDLE") RemoveHandler Application.Idle, AddressOf AcadIdle Dim oDwg As Document = Application.DocumentManager.MdiActiveDocument 'Make sure FirstEnergy CUIx file is loaded on startup, then turn of handler If Not modAcadUI.IsPartialCuiFileLoaded("FE2011") Then Dim iFILEDIA As Integer = Application.GetSystemVariable("FILEDIA") Dim iCMDECHO As Integer = Application.GetSystemVariable("CMDECHO") Application.SetSystemVariable("CMDECHO", 0) Application.SetSystemVariable("FILEDIA", iFILEDIA) Application.SetSystemVariable("CMDECHO", iCMDECHO) 'Call modAcadUI.LoadPartialCuiFile(oDwg, g_sSupportFilePath & "\FirstEnergy.cuix") Application.SetSystemVariable("FILEDIA", iFILEDIA) Application.SetSystemVariable("CMDECHO", iCMDECHO) End If Select Case _sIdleHandlerOwner Case "AcadBeginDoubleClick" Try _bTitleBlockDoubleClicked = False Dim frm As New frmTitleBlockEditor Autodesk.AutoCAD.ApplicationServices.Application.ShowModelessDialog(frm) Catch ex As Autodesk.AutoCAD.Runtime.Exception MsgBox(ex.Message.ToString) End Try Case Else End Select _sIdleHandlerOwner = "" RemoveHandler Application.Idle, AddressOf AcadIdle End Sub 'Private Sub AcadSelectionAdded(ByVal sender As Object, ByVal e As SelectionAddedEventArgs) 'End Sub 'AcadSelectionAdded Sub AcadDocumentLockModeChanged(ByVal sender As Object, ByVal e As Autodesk.AutoCAD.ApplicationServices.DocumentLockModeChangedEventArgs) 'Begin Sub '========= 'Set global DocumentLockMode variable _eDocumentLockMode = e.CurrentMode Debug.Print(e.GlobalCommandName.ToString) Select Case e.GlobalCommandName.ToString Case "BEDIT", "EATTEDIT", "CUILOAD" If _sIdleHandlerOwner = "AcadBeginDoubleClick" Then 'Cancel command, turn on idle event handler, and reset flag e.Veto() AddHandler Application.Idle, AddressOf AcadIdle End If Case Else Debug.Print(e.GlobalCommandName.ToString) End Select End Sub Private Sub AcadDWG_CommandEnded(ByVal sender As Object, ByVal e As Autodesk.AutoCAD.ApplicationServices.CommandEventArgs) Handles AcadDWG.CommandEnded Debug.Print("CommandEnded") End Sub Sub AcadEndDwgOpen(ByVal sender As Object, ByVal e As Autodesk.AutoCAD.ApplicationServices.DrawingOpenEventArgs) 'Dim oDwg As Document = Application.DocumentManager.MdiActiveDocument ''Make sure FirstEnergy CUIx file is loaded 'If Not modAcadUI.IsPartialCuiFileLoaded("FirstEnergy") Then ' Call modAcadUI.LoadPartialCuiFile(oDwg, g_sSupportFilePath & "\FirstEnergy.cuix") 'End If End Sub Sub AcadDocumentActivated(ByVal sender As Object, ByVal e As Autodesk.AutoCAD.ApplicationServices.DocumentCollectionEventArgs) 'Dim oDwg As Document = Application.DocumentManager.MdiActiveDocument ''Turn on AppIdle event when FirstEnergy CUIx file is not loaded 'If Not modAcadUI.IsPartialCuiFileLoaded("FirstEnergy") Then ' AddHandler Application.Idle, AddressOf AcadIdle 'End If End Sub End Class End Namespace
hi,
dont be upset. As you are new in this area so it will struggling hours. It also happend to me that I did not get simple issue. Now little bit familiar with API so less problem appears while want to do something. However lets talk about the point. While DLL is loaded , our handler will be added.
AddHandler Application.DocumentManager.DocumentCreated, AddressOf ReplaceMtextinTitleBlock
In the handler, you see that Application.DocumentManager.DocumentCreated is there. The meaning of this line is ReplaceMtextinTitleBlock sub will be fired whenever any document is created in the application. you can find details about events from .net developers guide through below link:
I think this code should work. If not please try to debug where it is blocking. I will try with your code and your drawing as well
mzakiralam,
After walking away and calming down. I studied the code You and _gile showed me. I found the error!!!
I needed to change the AddHandler from this AddHandler Application.DocumentManager.DocumentCreated, AddressOf ReplaceMtextinTitleBlock to
AddHandler Application.DocumentManager.DocumentActivated, AddressOf ReplaceMtextinTitleBlock.
Thanks to everyone for the help!!!!!
I will Kudos to all involved!!!!!
THANK YOU THANK YOU THANK YOU!!!!!!!!!!!!