2012-03-18 111 views
5

我用一个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; 
    } 
} 

回答

5

关于第一个问题:

  • 的跨线程的例外是故意抛出Debug模式。这意味着对大部分GUI控件内置的InvokeRequired进行(条件)代码检查。像小组一样。

  • 显然这个ToolstripLabel没有做这个检查。由于它不是来自控制,可能是因为它超出了本安全网的范围。

由于标准免责声明“的任何实例成员不能保证线程安全的”适用于ToolstripLabel设置文本的时候,我只想与正常InvokeRequired逻辑去。

+1

我认为这个答案解决了OP所问的问题,这就是为什么一个看起来不安全的呼叫并没有抛出异常。这一切都围绕着这样的事实:ToolStripLabel不是从Control派生的,因此不检查线程的安全性。它恰好适用,但正如其他人指出的那样,你不能指望永远保持真实。 – 2012-03-18 14:50:45

0

选择的优点是,它工作 :)

所有UI元素在主UI线程创建的,什么是从这个角度看问题,更重要的,是可以成为只能在该线程中使用

这就是为什么你的第一情况下失败,那就是你的情况下将工作的原因的原因。 Invoke()...会将所需的merhod调用重定向到主UI线程。

希望这会有所帮助。

+0

谢谢你的回答。你说'UnsafeThreadMethod'不应该工作,因为UI的东西是在不同的线程,但它以某种方式,这是我不明白。另外,最后一个问题是如果最好使用Invoke的东西或者'ProgressChanged'和'RunWorkerCompleted'(因为它们回到了正确的线程上,这会起作用)。 – pelz 2012-03-18 14:14:58

+0

第一个案件*有时*作品听起来很奇怪。第二种情况如何:考虑到在你的方法中访问UI元素,你必须*使用'Invoke'来将调用重定向到UI线程。它不能以其他方式工作。 – Tigran 2012-03-18 14:25:36

+0

不知何故,它会导致行为不确定。它可以随意修改,在服务包中修复。 – TomTom 2012-03-18 14:25:52

3

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

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

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

所以,是的,你打给Invoke的电话会起作用。然而,理解其他事件的作用可以帮助你理解为什么要用另一种方式。也许ProgressChanged事件适合更好?它也可以消除不必要的调用代码。

更新到第一Q-

我仍然无法找到的工具条不需要的invoke什么。事实上,我发现相反的使用谷歌搜索,如“toolstriplabel没有交叉线程异常”或“toolstriplabel调用”等。但是,正如henk提到的,toolstriplabel没有从控制继承,以便可以解释为什么不需要调用。不过,我的建议是假设它将像任何其他UI控件一样工作,并确保它在UI线程上更新以确保安全。 不依赖怪癖。有备无患,你永远不知道,如果这样的事情可能会发生变化,特别是因为它在逻辑上是一个UI项最..,

+0

谢谢你的回答。关于第一个问题:是的,它会更新标签。你对我的第二个问题的回答解决了很多问题。我认为在我的情况下'RunWorkerCompleted'就是要走的路。 – pelz 2012-03-18 14:27:30

+0

很高兴帮助。我更新了我的答案,在进一步研究后给出了我对标签的看法 – 2012-03-18 14:46:21

相关问题