Home > front end >  How to open VB.Net dialog window on top of form window that is opening the dialog?
How to open VB.Net dialog window on top of form window that is opening the dialog?

Time:10-29

Inside my Form1 class I have a method, named beginProcessingItems(), that operates on a list of items. This list can be very large so I am executing the beginProcessingItems method in a new thread, like so:

Dim processThread As New Thread(AddressOf beginProcessingItems)
processThread.Start()

Sometimes I need to show a dialog to collect additional information about an item from the user. This dialog is created and opened inside of the beginProcessingItems() method that is now running in a different thread from my Form1 window.

When I open the dialog, it is loading behind the Form1 window. I have tried various suggestions in other stack posts but they all end up causing an cross-thread operation not valid exception.

This is the code I currently have to open my dialog:

Public Sub beginProcessingItems()  
    ' ..do stuff .. and sometimes:
    Dim IDD As New ItemDetailsDialog()
    IDD.Location = ImportItemsButton.Location ' sets X,Y coords
    IDD.StartPosition = FormStartPosition.Manual
    IDD.TopMost = True
    'Note: Me = The Form1 object
    'IDD.Parent = Me '<-- also throws exception.
    If IDD.ShowDialog(Me) = DialogResult.OK Then ' <-- If I remove "Me" then the dialog opens but its underneath the Form1 window.
       ' .. do stuff with the dialog results
    End If
End Sub

And this is the exception message:

Cross-thread operation not valid: Control 'Form1' accessed from a thread other than the thread it was created on.

CodePudding user response:

I was able to fiddle code into something that works using delegates.

In the Form1 class, I added:

' = Created a public property to hold the dialog object ======
Public IDD As ItemDetailDialog = Nothing

' = Created a Delegate ======
Delegate Sub DelegateShowItemDetailDialog(ByVal Param1 As Integer, ByRef SomeClassObj As SomeClass, ByVal Param3 As Integer)

' = Created a method that instantiates the IDD  property and shows the dialog =====
Private Sub ShowItemDetailDialog(ByVal Param1 As Integer, ByRef SomeClassObj As SomeClass, ByVal Param3 As Integer)
    IDD = New ItemDetailDialog(Param1, SomeClassObj, Param3)
    IDD.Location = ImportItemsButton.Location ' sets X,Y coords
    IDD.StartPosition = FormStartPosition.Manual
    'IDD.TopMost = True ' <-- not needed
    'IDD.Parent = Me ' <-- not needed
    IDD.ShowDialog()        
End Sub

' = Instantiate the Delegate object into a public property 
' = that will get invoked from the beginProcessingItems() method running in a separate thread
Public ThreadShowItemDetailDialog As New  DelegateShowItemDetailDialog(AddressOf ShowItemDetailDialog)

I modified the beginProcessingItems method as follows:

Public Sub beginProcessingItems()  
    ' ..do stuff .. and sometimes:
    Me.Invoke(ThreadShowItemDetailsDialog, {Param1, SomeClassObj, Param3})
    ' dialog is now on top of the form1 window :-)
    If IDD.DialogResult = DialogResult.OK Then
       ' .. do stuff with the dialog results via the IDD class object
    End If
End Sub

Note that the Param1, SomeClassObj, and Param3 variables are shown as an example of how to pass parameter values to the dialog object. Obviously you would change them to whatever your dialog object instantiator needs.

CodePudding user response:

Try putting this into your Sub Form_Load:

CheckForIllegalCrossThreadCalls = False
  • Related