跨线程异常 - 仅限环境
控件只能由创建它的线程访问 - 我知道这一点。
- 我有一个 DataGridView 基于 BindingList<> 的数据源。
- 我有一个工作线程(非 GUI) 这有点花哨 计算/比较/等和 然后将对象添加到/编辑BindingList<>中。
- 在定时器上,GUI线程根据BindingList刷新自身。
只要我不在该环境中运行,这段代码就可以完美地工作。在 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 线程稍后检索它们...我不是在寻找解决方法,而是在寻找更多所以我对这个问题的答案很感兴趣:
为什么错误只出现在工作室中?
A control can only be accessed by the thread that created it - this much I know.
- I have a DataGridView with a
DataSource based on a BindingList<>. - I have a worker thread (non-GUI)
that runs some fancy
calculations/comparisons/etc and
then adds/edits an object to/in the BindingList<>. - On a timer, the GUI thread refreshes itself against the BindingList<>.
This code works flawlessly - as long as I'm not running in the environment. In the environment when the .Add() method is called on the BindingList<> I get this handy little error:
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
Notice how the name of the control being violated is blank... I would think that if the problem was with updating the BindingList<> it wouldn't matter if I was running in the environment or not. Notwithstanding, that's what I'm seeing. Moreover, the .Add() completes successfully even though the exception is thrown!!
Obviously, it's not a big deal in my production environment (yet?) since it only happens in Studio; and yes I could Invoke the GUI thread to perform the Add, or store the adds in a place for the GUI thread to retrieve them later... I'm not looking for a work-around but more so am interested in the answer to this question:
Why does the error only appear in studio?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果是 MDA(托管调试助手),不是运行时异常。 MDA 会告诉你,当你在做一些通常但不是 100% 总是会在生产代码中给你带来麻烦的事情时(最终,即使它看起来 99% 的时间都有效)你的机器)。
您应该调用 UI 线程来执行 Add 方法。
编辑:要100%彻底...没有Reflector(因为我的过期了-你在听Red Gate吗?!)我猜测Control类检查你是否在UI线程上,在后台线程上抛出异常如果不是,那么无论如何都会重新绘制 UI。由于后台线程已经添加了该项目,因此 UI 重绘会看到它并按预期将其绘制到 UI,但是您的后台线程仍然会看到异常,并且您要么在 catch 块中默默地吞下它,要么后台线程被终止(这在您的应用程序中可能是可以容忍的,例如 BG 线程是线程池线程)。
The error may occur only in VS if it is a MDA (Managed Debugging Assistant), not a runtime exception. MDAs are there to tell you when you are doing something that is usually, but not 100% always, something that will get you in trouble in production code (which this will, eventually, even if it seems to work 99% of the time on your machine).
You should be invoking to the UI thread to perform the Add method.
EDIT: To be 100% thorough... Without Reflector (since mine expired- are you listening Red Gate?!) I am guessing that the Control class checks to see whether you are on the UI thread, throws the exception on the background thread if you are not, and then redraws the UI anyway. Since the background thread has already added the item, the UI redraw sees it and draws it to the UI as expected, but your background thread is still seeing the exception, and you are either swallowing it silently in a catch block or the background thread is being terminated (which in your app is maybe tolerable, for inst. that BG thread is a threadpool thread).
该错误仅出现在 VS 中,因为它是一种诊断消息,试图告诉您有错误。在生产中,默认情况下禁用这些附加检查。因此,错误始终存在,但仅在调试时才会通知您。
我对多线程 WinForms 编程不太熟悉,但我假设由于您在另一个线程中调用该绑定列表上的 add ,因此更改通知也会在另一个线程中发生,并且由于您绑定了一个控件,因此它会在这样的时间内更改其状态通知。这意味着该控件是从错误的线程访问的,这是一个错误。
The error only appears in VS because it's a kind of diagnostic message trying to tell you that you have a bug. And in production those additional checks are disabled by default. So the bug is always there, but you're only notified while debugging.
I'm not too familiar with multithreaded WinForms programming, but I assume that since you call add on that binding list in another thread the change notifications happen in that other thread too, and since you bound a control it will change it's state during such a notification. Which means that the control is accessed from a wrong thread, which is a bug.
我认为这种情况一直在发生;但是,绑定错误通常会被默默地忽略(例如, BindingSource.DataError )。 Visual Studio 捕获已处理的异常 - 以突出显示失败。
如果您随后从另一个线程更新数据绑定控件 (DataGridView) 和绑定感知集合,则会带来麻烦。 “观察者”性质导致它在 UI 线程上进行更新。我过去曾解决过这个问题,但我认为您应该完全禁用数据绑定并手动更新。并且不要忘记手动更新和后台编辑应该两者同步访问,这样它们就不会冲突。
根据您执行绑定的具体方式,您应该能够禁用它并在循环中手动刷新它。
I think it is happening all the time; however, binding errors are usually silently ignored (for example, BindingSource.DataError ). Visual Studio catches exceptions that are handled - to highlight fail.
Having a data-bound control (DataGridView) and binding-aware collection is asking for trouble if you then update that from another thread. The "observer" nature leads it to do updates on the UI thread. I have hacked around this in the past, but I kinda think you should disable the data-binding completely and update manually. And don't forget that manual update and the background edits should both synchronise access so they don't fight.
Depending on how exactly you are doing the binding, you should be able to disable it and manually refresh it in a loop.