Explanation of invoke in C #

Time:2021-10-17

Use of invoke in C # ()

The difference between invoke and BeginInvoke

I have been confused about the use and concept of invoke and BeginInvoke. I have read some materials these two days and have some new understanding and understanding of the usage and principle of these two.

First of all, there are two cases of using invoke and BeginInvoke:

1. Invoke and BeginInvoke in control.

2. Invoke and BeginInvoke in delegate.

These two situations are different. We are going to talk about the first one. Let’s talk about the official definitions of invoke and BeginInvoke in. Net.

Control. Invoke (parameter delegate) method: executes the specified delegate on the thread that owns the underlying window handle of this control.

Control. BeginInvoke (parameter delegate) method: executes the specified delegate asynchronously on the thread where the underlying handle of the control is created.

According to these two concepts, we generally understand that the invoke table is synchronous and BeginInvoke represents asynchronous.

If your background thread does not need to wait after updating the status of a UI control, but continues to process down, you should use BeginInvoke for asynchronous processing.

If your background thread needs to operate the UI control and needs to wait until the operation is completed before continuing, you should use invoke.

Let’s do a test.

Example of invoke:

private void button1_Click(object sender, EventArgs e)
{
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"AAA");
            invokeThread = new Thread(new ThreadStart(StartMethod));
            invokeThread.Start();
            string a = string.Empty;
            For (int i = 0; I < 3; I + +) // adjust the number of cycles to see more clearly
            {
                Thread.Sleep(1000);   
                a = a + "B";
            }
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+a);
}

 private void StartMethod()
{
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"CCC");
            button1.Invoke(new invokeDelegate(invokeMethod));  
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"DDD");
}

 private void invokeMethod()
{
            //Thread.Sleep(3000);
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "EEE");
}

Conclusion: after we run, look at the running sequence of the program, 1AAA – > 3ccc and 1bbb – > 1EEE – > 3ddd.

Explanation: the main thread runs 1AAA, then 1bbb and the sub thread 3ccc execute at the same time, and then submit the invokemethod method to the main thread through invoke. Then the sub thread waits for the main thread to execute until the main thread completes the invokemethod method execution (during this period, it must wait for the main thread to execute the task submitted by invoke), and finally execute the sub thread 3ddd.

BeginInvoke example:

private void button1_Click(object sender, EventArgs e)
{
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"AAA");
            invokeThread = new Thread(new ThreadStart(StartMethod));
            invokeThread.Start();
            string a = string.Empty;
            For (int i = 0; I < 3; I + +) // adjust the number of cycles to see more clearly
            {
                Thread.Sleep(1000);   
                a = a + "B";
            }
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+a);
}

 private void StartMethod()
{
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"CCC");
            button1.BeginInvoke(new invokeDelegate(invokeMethod));  
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"DDD");
}

 private void beginInvokeMethod()
        {
            //Thread.Sleep(3000);
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "EEEEEEEEEEEE");
        }

Conclusion: we run and look at the results of execution: 1AAA – > 1bbb and 3ccc – > 1EEE and 3ddd.

Explanation: the main thread runs 1AAA, then 1bbb and the sub thread 3ccc execute at the same time, and then submit the invokemethod method to the main thread through BeginInvoke. Then the main thread executes 1EEE (the main thread completes its own task execution), and the sub thread continues to execute 3ddd.

Through the test and comparison of the two codes, we will find that the delegate methods submitted by invoke and BeginInvoke are executed in the main thread. In fact, according to the definitions of invoke and BeginInvoke, we need to look at this problem in the sub thread. In the invoke example, we will find that the DDD can not be executed until the delegate methods submitted by invoke are executed; In the BeginInvoke example, we will find that after the delegate method submitted by BeginInvoke, the child thread will continue to execute DDD without waiting for the delegate method to complete. Now let’s recall the concepts of invoke (synchronous) and BeginInvoke (asynchronous). In fact, what they mean is relative to the child thread. In fact, the call to the control is always executed by the main thread. Many of us don’t understand this synchronization and asynchrony, mainly because we choose the wrong reference. In fact, sometimes it is easy to understand wrong just by looking at the concept.

Resolve accessing the control from a thread that is not creating it

In multithreaded programming, we often need to update the interface display in the working thread, and it is wrong to directly call the interface control in multithreading. Invoke and BeginInvoke appear to solve this problem, so that you can safely update the interface display in multithreading.

The correct approach is to encapsulate the code involved in updating the interface in the worker thread into a method and call it through invoke or BeginInvoke. The difference between the two is that one causes the worker thread to wait, while the other does not.

The so-called “responding to operations while adding nodes” can always be relative, so that the burden of UI threads is not too large, because the correct update of the interface always needs to be done through the UI thread. What we need to do is to undertake most of the operations in the working thread, and put the pure interface update into the UI thread, In this way, the goal of reducing the burden of UI threads is achieved.

For example, you are starting a thread and want to update a textbox in the form in the thread method

using System.Threading; 

//Start a thread 
Thread thread=new Thread(new ThreadStart(DoWork)); 
thread.Start(); 

//Thread method 
private void DoWork() 
{ 
This. Textbox1. Text = "I am a text box"; 
} 

If you operate like the above, there will be exceptions in VS2005 or 2008 

The correct way is to use invoke \ BeginInvoke

using System.Threading;
namespace test
{
public partial class Form1 : Form
{
public delegate void MyInvoke(string str1,string str2);
public Form1()
{
InitializeComponent();


}
public void DoWork()
{
MyInvoke mi = new MyInvoke(UpdateForm);
This. BeginInvoke (MI, new object [] {"I am a text box", "haha"});
}
public void UpdateForm(string param1,string parm2)
{
this.textBox1.Text = param1+parm2;
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(DoWork));
thread.Start();
}
}
}

Pay attention to the use of agents!

It will be added later that threads are often used in the development of WinForm, and sometimes controls outside the thread need to be accessed in the thread, such as setting the text property of textbox, etc. If you set it directly, the program will report the exception of accessing the control from a thread that is not the thread that created it. Usually we can solve it in two ways. First, set the property of control. The second is through delegate, and there are two ways to delegate, one is the common way, and the other is anonymous. These are explained separately below

First, by setting a property value of control to false, we can_ Add: control. Checkforillegalcrossthreadcalls = false in the load method; To solve it. Setting to false means that calls from the wrong thread are not captured. In this way, no more errors will be reported when setting the text property of textbox in the thread.

Secondly, it is solved by the method of delegate.

Common delegation methods, such as:


delegate void SafeSetText(string strMsg);
private void SetText(string strMsg)
{
 if(textbox1.InvokeRequired)
 {
            SafeSetText objSet=new SafeSetText(SetText);
            textbox1.Invoke(objSet,new object[]{strMsg});

 }
 else
 {
   textbox1.Text=strMsg;
 }
}

When the value of textbox needs to be set in the thread, you can call the settext method. We can also use another way of delegation, that is, anonymous proxy, for example:


delegate void SafeSetText(string strMsg);
private void SetText2(string strMsg)
{
  SafeSetText objSet = delegate(string str)
   {
       textBox1.Text = str;
   }
   textBox1.Invoke(objSet,new object[]{strMsg});
}

This can also be achieved.

Personally, I think it’s better to use agency.

In c# 3.0 and later versions, there are lamda expressions, and anonymous delegates like the above have a more concise way to write them Net framework version 3.5 and later can better encapsulate methods with action. For example, the following wording can look very concise:

void ButtonOnClick(object sender,EventArgs e)
{
    this.Invoke(new Action(()=>
    {
        Button. Text = "close";
    }));
}

newest:

Invoke(() =>
{
 Button. Text = "close";
});

This is the end of this article on the use of invoke in c# for more relevant c# invoke content, please search the previous articles of developeppaer or continue to browse the relevant articles below. I hope you will support developeppaer in the future!