VB.NET线程。
我尝试从backgroundworker.do_work事件更新表单上的按钮文本,但它失败了,使用了通常的跨线程异常消息。
然而,纯粹的机会,我也试图从这个backgroundworker.do_work事件更新system.windows.form.toolstripstatuslabel中的文本,并且它可以工作。
问题:这是为什么?是因为与system.windows.form.toolstripstatuslabel有某种隐式共享行为吗?
谢谢大家。
答案 0 :(得分:1)
为什么会这样?
纯粹的机会。有时它可能会在其他人工作,它可能会崩溃。您永远不应该从未创建它们的线程(基本上是主GUI线程)更新任何GUI控件。
答案 1 :(得分:1)
这是ToolStripItem类的实现细节。它的作用类似于Control,但实际上并非来自Control。它是一个“无窗口”控件,使用其所有者的窗口来绘制自己。更改Text属性会导致调用Owner的Invalidate()方法。最终导致它被调用OnPaint方法并导致项目被绘制。在UI线程上。 Invalidate()是一个线程安全的方法,它只是设置一个内部“这个窗口需要一个Paint事件”状态位。
虽然这确实避免了典型的UI线程问题,例如死锁或彻头彻尾的崩溃,但它实际上并不完全是线程安全的。您可以在项目的paint方法运行的同时设置Text属性。使用未实际更新的可见文本结束。非常低的赔率,而不是零。
答案 2 :(得分:0)
您是如何创建/调用后台工作线程的?你应该做的事情......(这是C#,而不是VB)
// This would be a method in your form...
private void CallBackgroundWorker()
{
YourBackgroundWorkerClass BGW = new YourBackgroundWorkerClass();
BGW.WorkerReportsProgress = true;
BGW.ProgressChanged += MyFormsBGW_ProgressChanged;
BGW.RunWorkerAsync();
}
// this would be in your form too... to get feedback from worker to
// let the form's interface/control update itself
protected void MyFormsBGW_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
this.SomeButton.Text = "whatever";
}
然后,在你的后台工作者的某个地方,只需发出一个对ReportProgress()的调用......这个值几乎可以是任何东西,即使代表一个百分比,例如ReportProgress(100)。这将强制直接回调到FORM的线程(在UI线程上),让它更新它需要的内容,然后返回后台工作者继续。
答案 3 :(得分:0)
要记住Windows Forms
的一个重要漏洞抽象是在实际需要之前不创建窗口Handle
。 IE浏览器。实例化Form时不会创建句柄。相反,只有当我们第一次调用Show()/ ShowDialog()之类的函数时,才会创建lazily
并且有一个真正的窗口hwnd
。 IE浏览器。如果在工作线程完成中调用任何Show / ShowDilalog,则在工作线程上创建句柄。这里没有人要求表单的句柄,直到它作为工作线程完成其工作时发生的InvokeRequired
(发布操作异步)检查的一部分进行访问。这可能是您偶尔看到此问题的原因。