How to use control 'Invoke()' from second thread - 'Catch 22'

  • Thread starter Thread starter Guest
  • Start date Start date
G

Guest

I seem to run into a Catch 22 problem updating forms from a second thread. I have only been able to get the Invoke() function to work when the form was displayed using Application.Run(TheForm). When using ShowDialog() to display the form the Invoke() function does not return until the form closes. However, The application loses focus if I use Application.Run(TheNextForm) after the first one is closed.

The following code does not have the synchorization elements necessary to be rigorously correct but it demonstrates the problems I'm seeing even with proper synchronization. BTW, the forms are default created forms with MinimizeBox = False so I'm using the 'X' to close the form. I've tried lots of combinations of ShowDialog(frm) and Application.Run(frm) with one or the other problem occuring. Am I missing something?

Thanks in advance


Imports System.Threading
Public Class FocusClass
Private Shared f As Form
Public Shared Sub Main()
Dim f1 As Focus1
Dim f2 As Focus2

f1 = New Focus1
Application.Run(f1)

Dim th As New Thread(AddressOf UpdateLoop)
th.Start()
Do
f2 = New Focus2
f = f2
f2.ShowDialog() ' I've also tried Applicaiton.Run(f2)

f1 = New Focus1
f = f1
f1.ShowDialog() ' I've also tried Applicaiton.Run(f1)

Loop
End Sub

Private Shared Sub UpdateLoop()
Do
Thread.Sleep(500)

On Error Resume Next
f.Invoke(New EventHandler(AddressOf
UpdateItem))
On Error GoTo 0
Loop
End Sub

Private Shared Sub UpdateItem(ByVal sender As Object,
ByVal e As EventArgs)
f.Text = Format(Now, "hh:mm:ss")
End Sub

End Class
 
I seem to run into a Catch 22 problem updating forms from a second thread.
I have only been able to get the Invoke() function to work when the form
was displayed using Application.Run(TheForm). When using ShowDialog()
to display the form the Invoke() function does not return until the form
closes. However, The application loses focus if I use
Application.Run(TheNextForm) after the first one is closed.

Sounds like you have a main form and at some point want to close it and
show another form. The close on the first one will end the message loop
(started by Application.Run) and a second call to Application.Run will
not start up a second message pump (I believe this one is a bug in the
framework).

You might try creating an ApplicationContext and use it's MainForm
property to control how the message loop will exit (haven't tried this
before). Start with:

Dim ac As ApplicationContext = new ApplicationContext(firstForm)
Application.Run(ac)

The "ac" should be a variable accessible from firstForm. Before
firstForm exits, try changing the MainForm property:

dim secondForm as Form = new Secondform()
ac.MainForm = secondForm

Now close firstForm. I think that will keep the app running.
 
Hi Kohn,

Both solution work well for me. I read Patrick's post about second call to
Application.Run doesn't start a new message loop, it works for me as well.
And frankly I haven't heard for such a bug before. Calling Invoke to a form
shown with ShowDialog returns on timel. In other words. During my tests I
didn't have any of the probelms you described.
I rewrote your example in c# because that is the language I use and it works
fine. However, I see that your UpdateItem has EventHandler's prototype.
Calling Invoke as you do needs MethodInvoker delegate or you have to provide
values for EventHandler paramters (at least in c#). Anyways if it is not
code snippet of working test application I suspect that in the original one
you may have some error which is not shown in the code you posted.


B\rgds
100
Imports System.Threading
Public Class FocusClass
Private Shared f As Form
Public Shared Sub Main()
Dim f1 As Focus1
Dim f2 As Focus2

f1 = New Focus1
Application.Run(f1)

The code after this point will be executed when the application main form
(f1) gets closes.
 
It would have been helpful it I had mentioned that this is for the Compact Framework, which does not support Application.Run with the applicaitoncontext parameter. That is also why there are not arguments passed to the Invoke function because it is also nos supported by CF

My best results have been from running each form with Application.Run(frm) in its own thread. The thread closes after the form. I guess I'll have to make all my forms use this model.
 
Back
Top