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

时间:2012-03-18 13:58:27

标签: c# .net winforms multithreading exception-handling

我使用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不会抛出以下异常但EvenUnsaferThreadMethod会这样做。

  

跨线程操作无效:从>以外的线程访问控制'panelLoading'线程是在它上面创建的。

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

我认为我不能调用主线程创建的控件,必须使用ProgressChanged事件。发生了什么事?

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

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

3 个答案:

答案 0 :(得分:5)

对第一个问题:

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

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

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

答案 1 :(得分:3)

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

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

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

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

更新到第一个q

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

答案 2 :(得分:0)

第二选择的优势在于正常工作:)

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

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

希望这有帮助。