为什么我没有得到“跨线程操作无效”错误

我使用BackgroundWorker并执行此操作:

private void loadNewAsyncToolStripMenuItem_Click(object sender, EventArgs e) { this.Text = "RunWorkerAsync()"; backgroundWorkerLoading.RunWorkerAsync(); } private void backgroundWorkerLoading_DoWork(object sender, DoWorkEventArgs e) { UnsafeThreadMethod("hello"); EvenUnsaferThreadMethod(); } 

而现在这两种方法。

 private void UnsafeThreadMethod(string text) { toolStripLabelRssFeedData.Text = text; } private void EvenUnsaferThreadMethod() { panelLoading.Visible = true; } 

我不明白为什么UnsafeThreadMethod不会抛出以下exception,但EvenUnsaferThreadMethod会抛出exception。

跨线程操作无效:控制’panelLoading’从其创建的>线程以外的线程访问。

根据消息,因为toolStripLabelRssFeedData是在同一个线程上创建的,但事实并非如此。

我以为我不能调用主线程创建的控件,必须使用ProgressChanged事件。 这是怎么回事?

我还有第二个问题。 当我可以使用ProgressChanged时,这样做有什么好处? 我该怎么办?

 private void EvenUnsaferThreadMethod() { if (panelLoading.InvokeRequired) { panelLoading.Invoke(new MethodInvoker(() => { EvenUnsaferThreadMethod(); })); } else { panelLoading.Visible = true; } } 

对第一个问题:

  • 在调试模式下故意抛出跨线程exception。 这意味着对大多数GUI控件中内置的InvokeRequired进行(条件)代码检查。 像小组一样。

  • 显然,ToolstripLabel不进行此检查。 因为它不是来自Control,可能是因为它超出了本安全网的范围。

由于标准免责声明“任何实例成员都不保证是线程安全的”适用于ToolstripLabel,因此在设置Text时我会使用普通的InvokeRequired逻辑。

对于你的第一个问题,我并不完全确定,但是来自在线的评论似乎表明,有时这不会引发exception,但它不会更新标签。 这是这种情况吗? 您的标签是否会更新并且没有例外?

但是,我现在可以回答你的第二个问题。 ProgressChanged事件的确适用于它的声音。 应该调用它来让UI线程知道backgroundworker的状态,以便它可以适当地更新自己。 原始调用线程(在本例中为UI)是用于ProgressChanged线程,因此在更新时它不需要调用Invoke 。 但是,这应该只是为了显示后台工作人员的进度。

现在,如果它不是您尝试传递给调用方法的更新,那么我建议您只通过RunWorkerCompleted事件传回返回数据。 这将所有最终数据传递回原始(UI)线程,以便它可以更新UI而无需任何Invoke

所以,是的,你对Invoke会起作用。 但是,了解每个其他事件的用途可以帮助您理解为什么使用一种方式而不是另一种方式。 也许ProgressChanged事件适合更好? 它还可以使您的代码无法进行不必要的调用。

更新到第一个q

我仍然无法找到任何关于不需要调用的工具条。 事实上,我发现相反使用google搜索,如“toolstriplabel no cross thread exception”或“toolstriplabel invoke”等。但是,正如henk所提到的,toolstriplabel不会从控件inheritance,因此可以解释为什么不需要调用。 但是,我的建议是假设它将像任何其他UI控件一样,并确保它在UI线程上更新是安全的。 不要依赖怪癖 。 更好的安全而不是遗憾,你永远不知道这样的事情是否会发生变化,特别是因为它在逻辑上是最重要的UI项目..,

你的第二选择的优点是它的工作 🙂

所有UI元素都是在主UI线程上创建的,从这个问题的角度来看,更重要的是, 只能在该线程中获取

这就是为什么你的第一个案例失败的原因,这就是你的第二个案例将起作用的原因。 Invoke()...将所需的merhod调用重定向到主UI线程。

希望这可以帮助。