您的位置:首页 > 编程语言 > C#

C#学习笔记整理-线程间操作无效: 从不是创建控件“XXXXXXX”的线程访问它。

2016-01-12 17:25 369 查看
线程间操作无效: 从不是创建控件“XXXXXXX”的线程访问它。

线程外操作GUI控件的问题

如果从另外一个线程操作windows窗体上的控件,就会和主线程产生竞争,造成不可预料的结果,甚至死锁

方法1

Control.CheckForIllegalCrossThreadCalls = false;


不建议使用, CheckForIllegalCrossThreadCalls=false容许子线程随时更新UI,在同一个函数体内,不能保证自身事务的一致性

方法2

概念:

Invoke和BeginInvoke方法

Invoke:在拥有此控件的基础窗口句柄的线程上执行委托,类似同步方法,即在Invoke封送的方法被执行完毕前,Invoke方法不会返回,从而调用者线程将被阻塞。

BeginInvoke:在创建控件的基础句柄所在线程上异步执行委托,类似异步方法,该方法封送完毕后马上返回,不会等待委托方法的执行结束,调用者线程将不会被阻塞。

InvokeRequired属性

InvokeRequired:如果控件的 Handle 是在与调用线程不同的线程上创建的(说明您必须通过 Invoke 方法对控件进行调用),则为 true;否则为 false

//注:效果->在Backgroundworker中更新processBar的Value中的值
delegate void DelegUpdateUI(int i);//定义更新UI的委托
//更新UI的函数
void UpdateUI(int i)
{
if (this.InvokeRequired)//如果是在非创建控件的线程访问,即InvokeRequired=true
{
DelegUpdateUI dUpdateUI = new DelegUpdateUI(UpdateUI);
this.Invoke(dUpdateUI , new object[] { i });
}
else
{
this.progressBar1.Value = i>100?100:i;
}
}
//DoWorkEventHandler
public void DoWork(object sender, DoWorkEventArgs e)
{
int i = 0;
while (true)
{
System.Threading.Thread.Sleep(100);
UpdateUI(i++);
}
}


MethodInvoker委托

该委托可执行托管代码中声明为 void 且不接受任何参数的任何方法,在对控件的 Invoke 方法进行调用时或需要一个简单委托又不想自己定义时可以使用该委托。

MethodInvoker miUpdateUI = new MethodInvoker(UpdateUI);
int i=0;
void UpdateUI()
{
this.progressBar1.Value = i > 100 ? 100 : i;
}

public void DoWork(object sender, DoWorkEventArgs e)
{
while (true)
{
Thread.Sleep(100);
i++;
this.Invoke(miUpdateUI);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: