Importing an XREF from a Modeless Dialog

Importing an XREF from a Modeless Dialog

tristan.jonas8XAAW
Advocate Advocate
508 Views
4 Replies
Message 1 of 5

Importing an XREF from a Modeless Dialog

tristan.jonas8XAAW
Advocate
Advocate

Hi all 😄

I'm having some issues with a modeless dialog box that's inhibiting the importation of an XREF. Here's the only code that transpires before the dialog is generated:

 

Public Class Scanner_Command
    <CommandMethod("SCANNER")>
    Public Sub ScannerCommand()

        If scannerWindow Is Nothing OrElse scannerWindow.IsDisposed Then
            scannerWindow = New SCANNERWindow
        End If
 Autodesk.AutoCAD.ApplicationServices.Application.ShowModelessDialog(scannerWindow)
        scannerWindow.Size = New Size(868, 644)
        scannerWindow.MinimumSize = scannerWindow.Size
        scannerWindow.MaximumSize = scannerWindow.Size
        scannerWindow.DataGridView1.ColumnHeadersVisible = False
        scannerWindow.DataGridView1.RowHeadersWidth = 140

    End Sub
End Class

 


from there, a dialog is generated, with a button that does this:

 

Public Class ScannerWindow
    Private Sub Button8_Click(sender As Object, e As EventArgs) Handles Button8.Click
        Scanner_Command.LoadAndCopyTemplate()
    End Sub
End Class

 


which invokes this command:

 

    <CommandMethod("LOADTEST")>
    Public Shared Sub LoadAndCopyTemplate()

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

        Dim templatePath As String = "C:\TEMPLATE.dwg"
        Dim xrefName As String = "_EATEMPLATE" & DateTime.Now.ToString("yyyyMMddHHmmss")
        Dim insertionPoint As New Point3d(0, 0, 0)
        Dim paddingValue As Double = 50.0  ' Define your padding value here

        ' Define filter bounds
        Dim origFilterBounds As New Point3dCollection()
        origFilterBounds.Add(New Point3d(12932565.9598, 262220.6699, 0))
        origFilterBounds.Add(New Point3d(12932565.9598, 262683.1699, 0))
        origFilterBounds.Add(New Point3d(12933345.9598, 262683.1699, 0))
        origFilterBounds.Add(New Point3d(12933345.9598, 262220.6699, 0))

        ' Get padded filter bounds
        Dim paddedFilterBounds As Point3dCollection = GetPaddedCoordsBox(origFilterBounds, paddingValue)

        ' Attach and bind xref
        Dim xrefId As ObjectId = AttachAndBindXref(db, templatePath, xrefName)

        ' Extract required entities and add to database
        ExtractEntitiesWithinBounds(db, xrefId, paddedFilterBounds)

        ' Delete empty layers if there are any
        'DeleteEmptyLayers(db)

        ' Zoom to the block
        ZoomToPoint(insertionPoint, 462)  ' Replace 462 with the proper window width after adjustment
    End Sub

    Public Shared Function AttachAndBindXref(db As Database, filePath As String, blockName As String) As ObjectId
        Dim xrefId As ObjectId
        Using acTrans As Transaction = db.TransactionManager.StartTransaction()
            xrefId = db.AttachXref(filePath, blockName)
            acTrans.Commit()

            Using acTransBind As Transaction = db.TransactionManager.StartTransaction()
                If Not xrefId.IsNull Then
                    Dim xrefs As New ObjectIdCollection()
                    xrefs.Add(xrefId)
                    db.BindXrefs(xrefs, True)
                End If
                acTransBind.Commit()
            End Using
        End Using

        Return xrefId
    End Function

 


And it all finally culminates with a crash on this offending line:

xrefId = db.AttachXref(filePath, blockName)

and an eFileAccessErr unhandles exception. Some observations are that using the LOADTEST command works just fine! It's only when I try to invoke it from a dialog window that my problems begin, so I'm able to confirm the functionality of the script at least. Also it works when the dialog box is Modal but not Modeless, however my needs depend on it being modeless. I've tried disposing and closing and using events and everything else I can think of but nothing I do is working, any advice?

0 Likes
Accepted solutions (2)
509 Views
4 Replies
Replies (4)
Message 2 of 5

_gile
Consultant
Consultant
Accepted solution

Hi,

What if you call the command with SendStringToExecute. It is safer from a modeless UI, because it lets AutoCAD lock the document and switch to document context.

Public Class ScannerWindow
    Private Sub Button8_Click(sender As Object, e As EventArgs) Handles Button8.Click
	    Dim doc As Document = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
        doc.SendStringToExecute("LOADTEST ", false, false, true)
    End Sub
End Class


Gilles Chanteau
Programmation AutoCAD LISP/.NET
GileCAD
GitHub

0 Likes
Message 3 of 5

ActivistInvestor
Mentor
Mentor
Accepted solution

Try this (this reminds me of why I hate VB.NET):

 

Public Class ScannerWindow
    Private Sub Button8_Click(sender As Object, e As EventArgs) Handles Button8.Click
        Application.DocumentManager.ExecuteInCommandContextAsync(
            Async Function(o)
                Await Scanner_Command.LoadAndCopyTemplate()
            End Function, Nothing)
    End Sub
End Class

 

0 Likes
Message 4 of 5

tristan.jonas8XAAW
Advocate
Advocate

I was able to test both of them and they both work! I'm going to go with the Async function approach since I'd like to implement some other functionality in the button as well so I would prefer to avoid SendStringtoExecute functions. Also I totally agree about VB.NET, at my work we're finally moving away from VB.NET to C# as soon as this project is done! 

Thanks again!

0 Likes
Message 5 of 5

ActivistInvestor
Mentor
Mentor

Both Solutions are pretty much the same. Under the hood, the one I posted uses a built-in command to execute the function passed to it, which is started using SendStringToExecute().

 

You can make the whole thing a lot easier and reusable using a custom Button class 

like this one (sorry, C# only):

 

 

 

using AcRx = Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Internal;
// Must use one of these:
// using System.Windows.Controls;
// using System.Windows.Forms;

namespace Autodesk.AutoCAD.ApplicationServices.MyExtensions
{
   /// <summary>
   /// A specialization of System.Windows.Forms.Button 
   /// or System.Windows.Controls.Button that executes 
   /// its Click handler in the document execution context. 
   /// 
   /// This control is primarily-intended for use with
   /// modeless UI's
   /// 
   /// The click handler for this button runs in the command/
   /// document context, which allows you to abstract away code
   /// that does that manually.
   /// 
   /// From the Click handler of this button, it is safe to
   /// use Editor.Command(), and there's no need to lock the
   /// document. Effectively, the code in the Click handler
   /// executes in the same context as code that runs in a
   /// registered modal command.
   /// 
   /// This class can derive from either the WinForms or
   /// PresentationFramework Button class, depending on
   /// which framework is being used and is referenced:
   /// 
   ///    System.Windows.Forms.Button
   ///    System.Windows.Controls.Button
   ///    
   /// </summary>

   public class CommandButton : Button 
   {
      protected override async void OnClick()
      { 
         var docmgr = Application.DocumentManager;
         if(docmgr.Count == 0)
            throw new AcRx.Exception(AcRx.ErrorStatus.NoDocument);
         if(docmgr.IsApplicationContext)
            await docmgr.ExecuteInCommandContextAsync(async o => base.OnClick(), null);
         else
            base.OnClick();
      }
   }
}

 

 

 

If you convert the above to VB and include it in your project,  and change the  type of 'Button8' from Button to CommandButton, then your button's Click handler can be reduced to this:

 

 

' Change the type of 'Button8' from Button to CommandButton

Public Class ScannerWindow
    Private Sub Button8_Click(sender As Object, e As EventArgs) Handles Button8.Click
         Scanner_Command.LoadAndCopyTemplate()
    End Sub
End Class

 

0 Likes