Click here to Skip to main content
15,881,172 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,

We have an issue with an application where we are making a call to an asynchronous process on LostFocus of a TextBox, the asyncronous process then needs to be able to update the main form UI (or display a dialog from the main form UI) while running asynchronously.

We have thought about call backs and having it truely asynchronous but we need everything to execute in the correct order and this is for a data entry system where speed and accuracy of data entry is important.

Example code shows what we are trying to do and if you switch to BeginInvoke the order of processing is not correct.

<pre lang="vb">
Public Class Form1

    Private Sub TextBox1_LostFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.LostFocus

        ' execute the server subroutine
        Dim dlgt As New MethodInvoker(AddressOf Me.AsyncProcess)

        TextBox1.Text = "1"
        ' textbox should say 1

        ' call the server subroutine asynchronously, so the main thread is free
        Dim ar As IAsyncResult = dlgt.BeginInvoke(Nothing, Nothing)

        While ar.IsCompleted = False
            ' Application.DoEvents()
        End While
        ' textbox should now say 2

        TextBox1.Text = "3"
        ' textbox should now say 3
    End Sub

    Public Sub AsyncProcess()
        UpdateTextBox()
    End Sub

    Public Sub UpdateTextBox()
        If Me.InvokeRequired Then
            Me.Invoke(New MethodInvoker(AddressOf UpdateTextBox), "2")
        Else
            TextBox1.Text = "2"
        End If
    End Sub
End Class


Does anyone know how we can invoke something else on the main form thread while is is still busy processing the LostFocus event?

Thanks in advance.
Posted

Additional note to this. Although Application.DoEvents() will work in this scenario, it is NOT the solution as this fires off the event queue incorrectly and is highly unreliable.
 
Share this answer
 
Comments
Sergey Alexandrovich Kryukov 13-Dec-11 22:57pm    
I don't think that explanation is quite correct (it does not really fire any events; and what is done incorrectly?), but I voted 4 for important point: this call should be avoided. I tried to explain what it does; harder to explain why it should not be used, because it would need analysis of delicate detail. Please see my solution.
--SA
You cannot call anything related to UI from non-UI thread. Instead, you need to use the method Invoke or BeginInvoke of System.Windows.Threading.Dispatcher (for both Forms or WPF) or System.Windows.Forms.Control (Forms only).

You will find detailed explanation of how it works and code samples in my past answers:
Control.Invoke() vs. Control.BeginInvoke()[^],
Problem with Treeview Scanner And MD5[^].

See also more references on threading:
How to get a keydown event to operate on a different thread in vb.net[^],
Control events not firing after enable disable + multithreading[^].

It is very important to avoid Application.DoEvents by all means and use threads itself. This call simply blocks the calling code until all the events in the event queue of the application are handled. Essentially, this code makes waits until the event queue of current application is empty. This is very dangerous because this may never happen is some code generates additional events which is a normal situation. This call is sometimes used to split the UI thread into some code with sequential logic in a loop preserving some kind of responsiveness of the application by calling Application.DoEvents in a loop. Never do it. More often, such call remains in code as a result of useless attempts to change the order of event handling in case of dependency on such order.

—SA
 
Share this answer
 
v2
Comments
james.mason 13-Dec-11 23:14pm    
If you run the above example as is... this will "hang" the app as the UI thread is receiving 2 calls at the same time. However, if you change this to a BeginInvoke instead this runs fine, however the final value ends up being "2" instead of "3". This is because the invoked (aysnc) call waits until the main thread (The lost focus event) has finished before processing it.

Ideally we are wanting to ensure that the order of the events remains the same as they are called... i.e. value set to "1", then "2", then "3"

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900