Because of the recent research on how to add a waiting screen to the long-running method to prevent form prosthetic death, asynchronous delegation and Lambda expression are needed, so the relevant content is urgently supplemented, and the learning experience record is now available for reference.
Relevant blog posts:< Asynchronous delegation implements a waiting form (loading interface), which cancels operations when tasks are timed out>
This paper is mainly about simplification.< The Solution of Form Losing Response When Program Executes Task for Long Time and Causes False Death to Avoid Repeated Clicking on Button > One article code, more prominent problems.
I. Form prosthetic death
Create a new windows form application, pull in a button Button and a Label control in the form, and add the following code for the button click event:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'Temporary removal Button1 Button Click Event RemoveHandler Button1.Click, AddressOf Button1_Click '****************************************** 'Simulate long-term working code For i As Integer = 0 To 100 'Simulate long-term work Threading.Thread.Sleep(100) 'Display progress Me.Label1.Text = i.ToString & "%" Next '****************************************** 'Remember to recover after work Button1 Button Click Event AddHandler Button1.Click, AddressOf Button1_Click End Sub
When the loop is executed, the form cannot be dragged, the button is clicked without response, and Label can not display the progress of the work in real time until 100% is displayed directly at the end of the loop. The form is in a pseudo-dead state.
II. Synchronized Delegation
For ease of understanding, I encapsulate long-running code into a method and call it in a button click event.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'Temporary removal Button1 Button Click Event RemoveHandler Button1.Click, AddressOf Button1_Click '****************************************** 'Calling long working code Call aa() '****************************************** 'Remember to recover after work Button1 Button Click Event AddHandler Button1.Click, AddressOf Button1_Click End Sub Private Sub aa() For i As Integer = 0 To 100 'Simulate long-term work Threading.Thread.Sleep(100) 'Display progress Me.Label1.Text = i.ToString & "%" Next End Sub
Change to Delegate.Invoke call method:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'Temporary removal Button1 Button Click Event RemoveHandler Button1.Click, AddressOf Button1_Click '****************************************** 'Calling long working code 'Call aa() 'Change to delegate invocation method Dim method As MethodInvoker = New MethodInvoker(AddressOf aa) method.Invoke '****************************************** 'Remember to recover after work Button1 Button Click Event AddHandler Button1.Click, AddressOf Button1_Click End Sub
The built-in delegate type MethodInvoker is used here, which saves the trouble of declaring and defining delegates. The running code finds that the Delegate.Invoke method is the same as the direct invocation method, without any difference. Why use delegation? This is just to illustrate the problem. The use is the same as the need.
3. Asynchronous Delegation Solving Form Pseudo-Death
Change the method.Invoke code to method. BeginInvoke (Nothing), and when you execute the code, an error prompt pops up: "System. Invalid OperationException:" Invalid inter-thread operation: never access it from a thread that created the control "Label1". As shown in the picture:
One solution is to add the following sentence to the code of the constructor or form Load:
Control.CheckForIllegalCrossThreadCalls = False
This is an unsafe thread operation and can easily cause deadlocks, so it is not recommended to do so. Control.Invoke or Control.BeginInvoke methods are recommended. The complete code is as follows:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'Temporary removal Button1 Button Click Event RemoveHandler Button1.Click, AddressOf Button1_Click '****************************************** 'Calling long working code 'Call aa() 'Change to delegate invocation method Dim method As MethodInvoker = New MethodInvoker(AddressOf aa) 'method.Invoke 'Conversion to asynchronous delegation method.BeginInvoke(Nothing, Nothing) '****************************************** 'Remember to recover after work Button1 Button Click Event AddHandler Button1.Click, AddressOf Button1_Click End Sub Private Sub aa() For i As Integer = 0 To 100 'Simulate long-term work Threading.Thread.Sleep(100) 'Display progress 'Me.Label1.Text = i.ToString & "%" 'Modified to Dim Actiondelegate = New Action(Of Integer)(AddressOf bb) Me.Label1.Invoke(Actiondelegate, i) Next End Sub Private Sub bb(ByVal int As Integer) 'Display progress Me.Label1.Text = int.ToString & "%" End Sub
You can also change Me. Label 1. Invoke (Action delegate, i) to Me. Label 1. Begin Invoke (Action delegate, i) for testing.
IV. Delegate.Invoke, Delegate.BeginInvoke and Control.Invoke, Control.BeginInvoke
Through the above code run test, I believe you have a certain understanding of Delegate.Invoke, Delegate.BeginInvoke, Control.Invoke, Control.BeginInvoke, the following extracts from< Delegate.Invoke, Delegate.BeginInvoke and Control.Invoke, Control.BeginInvoke Article 1.
1. Delegate.Invoke (delegate synchronous call)
a. The Invoke method of delegation, which executes delegation in the current thread.
b. Blocking the current thread while delegating execution until the delegation has finished, the current thread will continue to execute downward.
c. Delegated Invoke method, similar to routine invocation of method.
2. Delegate.BeginInvoke (delegated asynchronous call)
a. The delegated BeginInvoke method, which executes delegation in the thread pool allocated sub-threads
b. Delegate execution does not block the main thread (calling the delegated BeginInvoke thread), and the main thread continues to execute downward.
c. Delegate execution blocks subthreads.
d. At the end of the delegation, if there is a return value, the sub-thread will pass the return value to the main thread; if there is a callback function, the sub-thread will continue to execute the callback function.
3. Control.Invoke (synchronous call)
(1) Call Control.Invoke in the main thread (UI thread)
a. Call Control.Invoke in the main thread (UI thread), first execute Invoke's method, then execute the code after Invoke.
(2) Call Control.Invoke in a subthread
A. Call Control.Invoke in the sub-thread. The sub-thread encapsulates the method invoked into a message, and sends the message to the UI window by Reister Windows Message () calling the API. The main thread continues to execute downward, and the sub-threads are blocked.
b. When the message is executed by the main thread, the sub-thread can continue to execute.
4. Control.BeginInvoke (asynchronous call)
(1) Call Control.BeginInvoke in the main thread (UI thread)
A. Call Control.BeginInvoke in the main thread (UI thread), encapsulate the method invoked into a message, and send the message to the UI window by Reister Windows Message () calling the API. First execute the code after Invoke, then execute the method of Invoke.
(2) Call Control.BeginInvoke in a subthread
A. Call Control.BeginInvoke in the subthread. The subthread encapsulates the method invoked into a message and sends the message to the UI window by using Register Windows Message () calling the API. The main thread continues to execute downward, and the sub-threads continue to execute downward.
b. Finally, the Invoke method is executed by the main thread.
It can be seen that Control.Invoke and Control.BeginInvoke all work on UI threads.
If you want to know more about it, the three articles overflowing vertically and horizontally in the blog park are well written.
1,On. Net Delegation and Threads: Creating Non-blocking Asynchronous Calls (I)
2,On. Net Delegation and Threads: Creating Non-blocking Asynchronous Calls (2)
3,On. Net Delegation and Thread-Solving Form False Death
Official Help Documents:
1,Visual Basic
2,Calling synchronous methods asynchronously
5. Lambda expression
The above example uses AddressOf to associate delegates. To make the code more readable, Lambda expressions can be used. The code is as follows:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 'Temporary removal Button1 Button Click Event RemoveHandler Button1.Click, AddressOf Button1_Click '****************************************** Dim method As MethodInvoker = Sub() 'Simulate long-term working code For i As Integer = 0 To 100 'Simulate long-term work Threading.Thread.Sleep(100) 'Display progress Dim Actiondelegate As Action(Of Integer) = Sub(int) Me.Label1.Text = int.ToString & "%" End Sub Me.Label1.Invoke(Actiondelegate, i) Next End Sub method.BeginInvoke(Nothing, Nothing) '****************************************** 'Remember to recover after work Button1 Button Click Event AddHandler Button1.Click, AddressOf Button1_Click End Sub
Lambda expression is actually an anonymous Sub process or Function function. Lambda expression can be used as a delegate type. When you assign lambda expression to a delegate, you can specify the parameter name, but omit its data type to get the data type from the delegate. For more information, please read the Official Help:
1,Lambda expression (Visual Basic)
2,How to: Create a Lambda expression (Visual Basic)
6. Built-in delegation types in. Net Framework
Some commonly used predefined delegates are provided in the. Net Framework, such as Action,Func,Predicate,MethodInvoker,EventHandler And so on. When using delegates, it is recommended to use these delegate types as much as possible, rather than defining more delegate types in your code. This not only reduces the number of types in the system, but also simplifies the code. These delegation types should meet most of the requirements.
For example, when using the Method Invoker delegate type, you can omit the declaration part: Public Delegate Sub Method Invoker ()
Namely:
Public Delegate Sub MethodInvoker() Dim method As MethodInvoker = New MethodInvoker(AddressOf aa)
and
Dim method As MethodInvoker = New MethodInvoker(AddressOf aa)
It's the same. There's no need to define delegation.