Error:线程间操作无效: 从不是创建控件**的线程访问它
这个问题延续至文件夹拷贝的功能,因为可能遇到文件夹内容很大,需要给出详细信息的情况。
通过对Thread.Start()方法的运用,知道了类中定义代理的用途,可以与控件交互。查阅了一些资料,先对Thread.Start()方法进行一个描述:
在C#中,线程入口是通过ThreadStart代理(delegate)来提供的,你可以把ThreadStart理解为一个函数指针,指向线程要执行的函数,当调用C# Thread.Start()方法后,线程就开始执行ThreadStart所代表或者说指向的函数。
而在程序调用中遇到的如题所示的错误,分析原因如下:因为线程所调用的对象生命周期不存在此线程中,所调用的控件是另一个线程所创建的,所以,线程可以调用它所创建的控件,而不是其他控件所声明的。
解决方法:
(1)法一:VS2003兼容方法处理,如下:
publicForm1()
{
InitializeComponent(); Control.CheckForIllegalCrossThreadCalls=false;
}
方法二:微软建议作法,使用委托来修改主线程控件的属性。
(2)1. 可以在load时将CheckForIllegalCrossThreadCalls 属性的值设置为 false 。这样进行非安全线程访问时,运行环境就不去检验它是否是线程安全的。
2. 利用委托机制实现线程安全。上面的代码可以更改如下:
建立一个委托:delegate void SetLabelCallBack();
原来:
- private void tc_thread_SelectedIndexChanged(object sender, EventArgs e)
- {
- if (tc_timer.SelectedTab.Equals(tab1))
- tab1.text = "showing tab1......";
- else if (tc_timer.SelectedTab.Equals(tab2))
- {
- try
- {
- Thread myThread = new Thread(new ThreadStart(SetLabel));
- myThread.Start();
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message);
- }
- }
- }
- private void SetLabel()
- {
- myLabel.text = "showing tab2......";
- }
修改后: - private void tc_thread_SelectedIndexChanged(object sender, EventArgs e)
- {
- if (tc_timer.SelectedTab.Equals(tab1))
- tab1.text = "showing tab1......";
- else if (tc_timer.SelectedTab.Equals(tab2))
- {
- try
- {
- Thread myThread = new Thread(new ThreadStart(SetLabel));
- myThread.Start();
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message);
- }
- }
- }
- private void SetLabel()
- {
- if(tc_thread.InvokeRequired)
- {
- SetLabelCallBack labDele = new SetLabelCallBack(SetLabel);
- this.Invoke(labDele, new object[]{});
- }
- else
- {
- myLabel.text = "showing tab2......";
- }
- }