In c #, multiple threads are used to access the control in winform. The Inter-thread operation is invalid.

Source: Internet
Author: User

When we use winform applications, we usually encounter the problem of using the control information on the multi-threaded control interface. However, we cannot use traditional methods to solve this problem. I will introduce it in detail below.

First, let's look at the traditional method:

Public partial class Form1: Form
{
Public Form1 ()
{
InitializeComponent ();
}
Private void Form1_Load (object sender, EventArgs e)
{
Thread thread = new Thread (ThreadFuntion );
Thread. IsBackground = true;
Thread. Start ();
}
Private void ThreadFuntion ()
{
While (true)
{
This. textBox1.Text = DateTime. Now. ToString ();
Thread. Sleep (1000 );
}
}
}

Run this code and we will see that the system throws an exception: Cross-thread operation not valid: Control 'textbox1' accessed from a thread other than the thread it was created on. this is because. net 2.0 and later enhanced the security mechanism, and does not allow direct cross-thread access to control attributes in winform. So how can we solve this problem? Several solutions are provided below.

In the first solution, we add the following code in the Form1_Load () method:

Private void Form1_Load (object sender, EventArgs e)
{
Control. checkforillegalcrossthreadcils = false;
Thread thread = new Thread (ThreadFuntion );
Thread. IsBackground = true;
Thread. Start ();
}
After this code is added, the program can run normally. This code means that in this class, we do not check whether cross-thread calls are legal (if this sentence is not added, the operation is not abnormal, it indicates that the system and the default mode are not checked ). However, this method is not advisable. We can view the definition of the checkforillegalcrossthreadcils attribute and find that it is static. That is to say, no matter where the value is modified in the project, it will take effect globally. In addition, we usually check whether cross-thread access is abnormal. If someone else in the project modifies this attribute, our solution fails and we have to adopt another solution.

The second solution is to use delegate and invoke to control information from other threads. Many people write this control method on the Internet. However, I have read many such posts and it seems that there is no problem, but it has not actually solved this problem, first, let's look at the imperfect methods on the network:

Public partial class Form1: Form
{
Private delegate void FlushClient (); // proxy
Public Form1 ()
{
InitializeComponent ();
}
Private void Form1_Load (object sender, EventArgs e)
{
Thread thread = new Thread (CrossThreadFlush );

Thread. IsBackground = true;
Thread. Start ();
}

Private void CrossThreadFlush ()
{
// Bind the proxy to the Method
FlushClient fc = new FlushClient (ThreadFuntion );
This. BeginInvoke (fc); // call the proxy
}
Private void ThreadFuntion ()
{
While (true)
{
This. textBox1.Text = DateTime. Now. ToString ();
Thread. Sleep (1000 );
}
}
}

In this way, we can see that the exception of cross-thread access does not exist. However, a new problem occurs and the interface does not respond. Why does this problem occur? We just need to refresh the new thread infinitely and theoretically it will not affect the main thread. Otherwise, this method is equivalent to "injecting" The New thread into the main control thread, and it achieves the control of the main thread. As long as this thread does not return, the main thread will never respond. Even if the new thread does not use an infinite loop, it can return. The use of multithreading in this way also loses its original meaning.

Now let's take a look at the recommended solution:

Public partial class Form1: Form
{
Private delegate void FlushClient (); // proxy
Public Form1 ()
{
InitializeComponent ();
}
Private void Form1_Load (object sender, EventArgs e)
{
Thread thread = new Thread (CrossThreadFlush );
Thread. IsBackground = true;
Thread. Start ();
}

Private void CrossThreadFlush ()
{
While (true)
{
// Place sleep and infinite loop outside of waiting for Asynchronization
Thread. Sleep (1000 );
ThreadFunction ();
}
}
Private void ThreadFunction ()
{
If (this. textBox1.InvokeRequired) // wait for Asynchronization
{
FlushClient fc = new FlushClient (ThreadFunction );
This. Invoke (fc); // call the refresh method through the proxy
}
Else
{
This. textBox1.Text = DateTime. Now. ToString ();
}
}
}

After running the above code, we can see that the problem has been solved. By waiting for Asynchronization, we will not always hold the control of the main thread, in this way, you can control winform multi-threaded controls without cross-thread call exceptions.

 

For the questions raised by Shen Shan laolin, I recently found a better solution and used the asynchronous call of delegate. Let's take a look:

 

Public partial class Form1: Form
{
Private delegate void FlushClient (); // proxy
Public Form1 ()
{
InitializeComponent ();
}
Private void Form1_Load (object sender, EventArgs e)
{
Thread thread = new Thread (CrossThreadFlush );
Thread. IsBackground = true;
Thread. Start ();
}

Private void CrossThreadFlush ()
{

FlushClient fc = new FlushClient (ThreadFunction );

Fc. BeginInvoke (null, null );
}
Private void ThreadFunction ()
{

While (true)
{
This. textBox1.Text = DateTime. Now. ToString ();
Thread. Sleep (1000 );
}

}
}

This method can also be directly simplified to (because the asynchronous mode of delegate is an asynchronous thread ):

 

Public partial class Form1: Form
{
Private delegate void FlushClient (); // proxy
Public Form1 ()
{
InitializeComponent ();
}
Private void Form1_Load (object sender, EventArgs e)
{
FlushClient fc = new FlushClient (ThreadFunction );

Fc. BeginInvoke (null, null );
}

Private void ThreadFunction ()
{

While (true)
{
This. textBox1.Text = DateTime. Now. ToString ();
Thread. Sleep (1000 );
}

}
}

When we use winform applications, we usually encounter the problem of using the control information on the multi-threaded control interface. However, we cannot use traditional methods to solve this problem. I will introduce it in detail below.

First, let's look at the traditional method:

Public partial class Form1: Form
{
Public Form1 ()
{
InitializeComponent ();
}
Private void Form1_Load (object sender, EventArgs e)
{
Thread thread = new Thread (ThreadFuntion );
Thread. IsBackground = true;
Thread. Start ();
}
Private void ThreadFuntion ()
{
While (true)
{
This. textBox1.Text = DateTime. Now. ToString ();
Thread. Sleep (1000 );
}
}
}

Run this code and we will see that the system throws an exception: Cross-thread operation not valid: Control 'textbox1' accessed from a thread other than the thread it was created on. this is because. net 2.0 and later enhanced the security mechanism, and does not allow direct cross-thread access to control attributes in winform. So how can we solve this problem? Several solutions are provided below.

In the first solution, we add the following code in the Form1_Load () method:

Private void Form1_Load (object sender, EventArgs e)
{
Control. checkforillegalcrossthreadcils = false;
Thread thread = new Thread (ThreadFuntion );
Thread. IsBackground = true;
Thread. Start ();
}
After this code is added, the program can run normally. This code means that in this class, we do not check whether cross-thread calls are legal (if this sentence is not added, the operation is not abnormal, it indicates that the system and the default mode are not checked ). However, this method is not advisable. We can view the definition of the checkforillegalcrossthreadcils attribute and find that it is static. That is to say, no matter where the value is modified in the project, it will take effect globally. In addition, we usually check whether cross-thread access is abnormal. If someone else in the project modifies this attribute, our solution fails and we have to adopt another solution.

The second solution is to use delegate and invoke to control information from other threads. Many people write this control method on the Internet. However, I have read many such posts and it seems that there is no problem, but it has not actually solved this problem, first, let's look at the imperfect methods on the network:

Public partial class Form1: Form
{
Private delegate void FlushClient (); // proxy
Public Form1 ()
{
InitializeComponent ();
}
Private void Form1_Load (object sender, EventArgs e)
{
Thread thread = new Thread (CrossThreadFlush );

Thread. IsBackground = true;
Thread. Start ();
}

Private void CrossThreadFlush ()
{
// Bind the proxy to the Method
FlushClient fc = new FlushClient (ThreadFuntion );
This. BeginInvoke (fc); // call the proxy
}
Private void ThreadFuntion ()
{
While (true)
{
This. textBox1.Text = DateTime. Now. ToString ();
Thread. Sleep (1000 );
}
}
}

In this way, we can see that the exception of cross-thread access does not exist. However, a new problem occurs and the interface does not respond. Why does this problem occur? We just need to refresh the new thread infinitely and theoretically it will not affect the main thread. Otherwise, this method is equivalent to "injecting" The New thread into the main control thread, and it achieves the control of the main thread. As long as this thread does not return, the main thread will never respond. Even if the new thread does not use an infinite loop, it can return. The use of multithreading in this way also loses its original meaning.

Now let's take a look at the recommended solution:

Public partial class Form1: Form
{
Private delegate void FlushClient (); // proxy
Public Form1 ()
{
InitializeComponent ();
}
Private void Form1_Load (object sender, EventArgs e)
{
Thread thread = new Thread (CrossThreadFlush );
Thread. IsBackground = true;
Thread. Start ();
}

Private void CrossThreadFlush ()
{
While (true)
{
// Place sleep and infinite loop outside of waiting for Asynchronization
Thread. Sleep (1000 );
ThreadFunction ();
}
}
Private void ThreadFunction ()
{
If (this. textBox1.InvokeRequired) // wait for Asynchronization
{
FlushClient fc = new FlushClient (ThreadFunction );
This. Invoke (fc); // call the refresh method through the proxy
}
Else
{
This. textBox1.Text = DateTime. Now. ToString ();
}
}
}

After running the above code, we can see that the problem has been solved. By waiting for Asynchronization, we will not always hold the control of the main thread, in this way, you can control winform multi-threaded controls without cross-thread call exceptions.

 

For the questions raised by Shen Shan laolin, I recently found a better solution and used the asynchronous call of delegate. Let's take a look:

 

Public partial class Form1: Form
{
Private delegate void FlushClient (); // proxy
Public Form1 ()
{
InitializeComponent ();
}
Private void Form1_Load (object sender, EventArgs e)
{
Thread thread = new Thread (CrossThreadFlush );
Thread. IsBackground = true;
Thread. Start ();
}

Private void CrossThreadFlush ()
{

FlushClient fc = new FlushClient (ThreadFunction );

Fc. BeginInvoke (null, null );
}
Private void ThreadFunction ()
{

While (true)
{
This. textBox1.Text = DateTime. Now. ToString ();
Thread. Sleep (1000 );
}

}
}

This method can also be directly simplified to (because the asynchronous mode of delegate is an asynchronous thread ):

 

Public partial class Form1: Form
{
Private delegate void FlushClient (); // proxy
Public Form1 ()
{
InitializeComponent ();
}
Private void Form1_Load (object sender, EventArgs e)
{
FlushClient fc = new FlushClient (ThreadFunction );

Fc. BeginInvoke (null, null );
}

Private void ThreadFunction ()
{

While (true)
{
This. textBox1.Text = DateTime. Now. ToString ();
Thread. Sleep (1000 );
}

}
}

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.