WinForm不同线程访问同一控件导致的不安全错误解决办法
错误原因分析
造成这一错误的原因通常是非创建该控件的线程操作了这个控件,比如主线程创建了窗口A,分线程要关掉窗口A。因为程序并不能确定主线程是不是在操作这个窗口,所以盲目的关闭这个窗口会造成不可预料的错误!(当然,只要你逻辑清楚是不会出错的,但是编译器还是要强制进行安全检查)
解决方案
对于这个问题,最好的解决方案是通过创建该控件的进程操作这个控件,那么怎么在分线程中找到创建该控件的线程呢?答案是使用代理(委托),把分线程不能操作的方法包成代理方法,让分线程中被操作的控件执行这个代理就可以了。
代码实现
场景假设
假设通过FormA去创建FormB,之后在通过新线程去关闭FormB
FormA去创建FormB
private void button1_Click(object sender, EventArgs e)
{
FormB fb = new FormB();
fb.ShowDialog();
}
FormA创建新线程管理FormB
private void button1_Click(object sender, EventArgs e)
{
//其中closeFormMethod为你要管理控件的方法;
Thread th = new Thread( new ThreadStart(closeFormMethod) );
th.Start();
FormB fb = new FormB();
fb.ShowDialog();
}
分线程中创建代理,并用代理去执行分线程中不能执行的方法
private delegate void HideFrom();
private void closeFormMethod()
{
//延时3S是为了保证窗口B确确实实被创建了
Thread.Sleep(3000);
HideFrom hideFrom = new HideFrom(fb.Close);
fb.Invoke(hideFrom);
}
解决方案分析
这个代理方法并不是真正由分线程执行的,而是由创建控件的线程执行的,当控件调用invoke方法的时候,会通过控件的控件树找到创建这个控件的父控件,从而找到父控件中创建这个控件的线程,并由这个线程调用代理方法。从而做到线程安全。