跨线程异常 - 仅限环境

时间:2011-06-01 19:32:44

标签: c# winforms multithreading marshalling

控件只能由创建它的线程访问 - 我知道这一点。

  1. 我有一个带有的DataGridView DataSource基于BindingList<>。
  2. 我有一个工作线程(非GUI) 有点花哨 计算/比较/等等 然后在BindingList<>。
  3. 中添加/编辑对象
  4. 在计时器上,GUI线程会针对BindingList<>刷新自己。
  5. 这段代码完美无瑕 - 只要我没有在环境中运行。在BindingList<>上调用.Add()方法的环境中我得到了这个方便的小错误:

    An Exception has occurred
    EXCEPTION : Cross-thread operation not valid: Control '' accessed from a thread other than the thread it was created on.
    IN METHOD : get_Handle
    AT LINE   : 0
    CLASS     : System.Windows.Forms.Control
    

    注意违反控件的名称​​是空白的 ...我认为如果问题是更新BindingList<>如果我在环境中跑步也没关系。尽管如此,这就是我所看到的。 此外,即使抛出异常,.Add()也会成功完成!!

    显然,这在我的生产环境中并不是什么大问题(但是?)因为它只发生在Studio中;并且是的我可以调用GUI线程来执行添加,或者将添加内容存储在GUI线程的位置以便以后检索它们...我不是在寻找解决方法但是更多所以我对这个问题的答案感兴趣:

    为什么错误只出现在工作室?

3 个答案:

答案 0 :(得分:4)

如果它是MDA(Managed Debugging Assistant),则错误可能仅发生在VS中,而不是运行时异常。 MDA可以告诉你,当你做的事情通常,但不是100%总是,会让你在生产代码中遇到麻烦(最终,即使它似乎在99%的时间都在工作你的机器。)

您应该调用UI线程来执行Add方法。

编辑:要100%彻底...没有反射器(因为我的过期 - 你在听红门吗?!)我猜测Control类检查你是否在UI线程上,抛出异常如果你不是后台线程,那么无论如何都要重绘UI。由于后台线程已经添加了项目,UI重绘会看到它并按预期将其绘制到UI,但是您的后台线程仍然看到异常,并且您要么在catch块中静默吞咽它,要么后台线程是被终止(在你的应用程序中可能是可以容忍的,因为那个BG线程是线程池线程)。

答案 1 :(得分:3)

该错误仅出现在VS中,因为它是一种诊断消息,试图告诉您有错误。在生产中,默认情况下禁用这些附加检查。因此,错误始终存在,但只有在调试时才会收到通知。

我不太熟悉多线程WinForms编程,但我认为,因为你在另一个线程中调用add绑定列表,变更通知也会发生在另一个线程中,并且由于你绑定了一个控件,它将改变它的状态在这样的通知期间。这意味着从错误的线程访问控件,这是一个错误。

答案 2 :(得分:1)

我认为这种情况一直在发生;但是,绑定错误通常会被忽略(例如,BindingSource.DataError)。 Visual Studio捕获处理的异常 - 突出显示失败。

如果您从另一个线程更新数据绑定控件(DataGridView)和绑定感知集合,则会遇到麻烦。 “观察者”性质导致它在UI线程上进行更新。我过去一直在讨论这个问题,但我认为你应该完全禁用数据绑定并手动更新。并且不要忘记手动更新和后台编辑应该两者同步访问,这样他们就不会打架。

根据完全的方式进行绑定,您应该能够禁用它并在循环中手动刷新它。