Solution to cross-thread control access in C #

Source: Internet
Author: User

Net prohibits cross-thread access to controls in principle, because this may cause errors. We recommend that you use a proxy to indirectly operate controls not created by the same thread.

The second method is to prohibit the compiler from checking cross-thread access, which can be used for access, but control. checkforillegalcrossthreadcils = false is not guaranteed when no error occurs;

Recently I am working on a project and have encountered cross-thread access to page controls. however, an error is always prompted. You cannot modify the value of the control in the thread where the control is created in other threads. Later, the anonymous proxy is used, and the result is easily solved. the solution is as follows:
First, create a ListBox, lable.
Using system;
Using system. Collections. Generic;
Using system. componentmodel;
Using system. Data;
Using system. drawing;
Using system. text;
Using system. Windows. forms;
Using system. Threading;

Namespace accesscontrol
{
Public partial class form1: Form
{
Public form1 ()
{
Initializecomponent ();
}

Private void form1_load (Object sender, eventargs E)
{
Thread newthread = new thread (New threadstart (backgroundprocess ));
Newthread. Start ();

}

/// <Summary>
/// Define a proxy
/// </Summary>
Private delegate void crossthreadoperationcontrol ();

Private void backgroundprocess ()
{
// Instantiate the proxy as an anonymous proxy
Crossthreadoperationcontrol crossdelete = delegate ()
{
Int I = 1;
While (I <5)
{
// Add a project to the list box
Listbox1.items. Add ("item" + I. tostring ());
I ++;
}
Label1.text = "I access this lable in the new thread! ";
Listbox1.items. Add (label1.text );
};
Listbox1.invoke (crossdelete );
}

}
}
I hope this tips will be helpful for your learning and work. If you have a better solution to cross-thread access control problems, I would like to share it with you.

C # Cross-thread access control runtime error. You can solve this problem by using methodinvoker:

Original code:

Private void btnok_click (Object sender, eventargs E)
{
Tslinfo. Text = "Please wait ...";

Thread TD = new thread (New threadstart (run ));
TD. Start ();
}

/// <Summary>
/// Thread method
/// </Summary>
Private void run ()
{
This. tslinfo. Text = "ready ";
}
After modification:

Private void btnok_click (Object sender, eventargs E)
{
Tslinfo. Text = "Please wait ...";

Thread TD = new thread (New threadstart (threadrun ));
TD. Start ();
}

/// <Summary>
/// Original thread method
/// </Summary>
Private void run ()
{
This. tslinfo. Text = "ready ";
}

/// <Summary>
/// Thread method
/// </Summary>
Private void threadrun ()
{
Methodinvoker in = new methodinvoker (run );
This. begininvoke (in );
}

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 = new flushclient (threadfunction );

Flushclient. 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)
{
Thread thread = new thread (crossthreadflush );
Flushclient = new flushclient (threadfunction );

Flushclient. 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.