C# - BackgroundWorker 不断更新控件:错误!
出于某种原因,我传统上在 C# 中使用 BackgroundWorkers 时遇到很多麻烦;他们的概念似乎确实难住了我,所以我希望这是一个相当基本的问题,并且可以很容易地纠正......
我有两种使用 .NET 远程处理来回通信的表单。现在,更改 Form1 上的设置会导致 Form2 上的某些内容发生变化,效果很好。但是,现在我需要以另一种方式使同样的事情工作(更改 Form2 上的某些内容会导致 Form1 更新),并且我不能以同样的方式执行此操作(由于设计的限制,我不能让 Form2 发送更改)到表格 1)。现在,我尝试在 Form1 上使用 BackgroundWorker 来不断调用每个子控件(放置在 Form1 上)上的“Update()”方法。这些控件中的每一个都可以从 Form2 中获取其等效设置的当前状态并更新自身(这很有效;“Update()”方法已被视为在 Form1 的初始化中起作用)。
这就是我的问题出现的地方。我不确定如何让BackgroundWorker在每个表单上不断调用“Update()”,因此在我的“DoWork()”方法中,我有一个“while(true)”循环,并且在其中BackgroundWorker调用“Update”每个子控件的 ()' 方法,然后休眠很短的时间,然后重复。
通过这种方式,我收到“InvalidOperationException 未由用户代码处理”错误,并详细说明“跨线程操作无效:控制‘comboBox_BGColor’是从创建它的线程以外的线程访问的。”现在,我基本上知道这意味着什么,也明白为什么会发生,但是,我不确定该做什么不同,或者如何改变事情以使其按预期工作。有人对此或我使用BackgroundWorker 的方式有任何提示吗?非常感谢您提供任何信息并花时间阅读本文!
I traditionally have a lot of trouble with BackgroundWorkers in C# for some reason; their concept really seems to stump me, so I'm hoping this is a fairly basic issue and something the can be corrected easily enough...
I have two forms that use .NET remoting to communicate back and forth. Right now, changing a setting on Form1 causes something to change on Form2 and that works great. However, now I need to make the same thing work the other way (changing something on Form2 causes Form1 to update) and I can't do it the same way (I cannot, due to restrictions in the design, have Form2 send the change to Form1). Right now, I'm trying to use a BackgroundWorker on Form1 to constantly call an 'Update()' method on each of the subcontrols (which are placed on Form1). Each of these controls have the means to grab the current state of their equalivalent settings from Form2 and update themselves (this works well; the 'Update()' method is already seen to be working on the initialization of Form1).
Here's where my issue comes up. I was unsure on how make the BackgroundWorker constantly call 'Update()' on each of the forms, so in my 'DoWork()' method, I have a "while(true)" loop and within that the BackgroundWorker calls the 'Update()' method of each subcontrol, then sleeps for a very short time, then repeats.
Doing it this way, I get an "InvalidOperationException was unhandled by user code" error with details stating that "Cross-thread operation not valid: Control 'comboBox_BGColor' accessed from a thread other than the thread it was created on." Now, I basically know what this means and I understand why it happened, however, I'm unsure what to do differently or how to change things to make it work as desired. Anyone have any tips on this or the way I'm using BackgroundWorker? Thanks a lot for any information and for taking the time to read this!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
UI 控件具有线程关联性。除了 UI 线程之外,您不应该从任何线程触摸控件(用于读取或写入)。如果
BackgroundWorker
主要与 UI 对话,那么您可能最好只使用Timer
控件,从而避免调用调用或
BeginInvoke
。然而,通常我更喜欢这里更多基于“观察者”的设计,带有更改通知事件(
FooChanged
或INotifyPropertyChanged
)和事件-导致 UI 反映更改的处理程序。UI controls have thread affinity. You shouldn't touch the controls (for read or write) from any thread except the UI thread. If the
BackgroundWorker
is talking primarily to the UI, you would probably be better off with just aTimer
control, avoiding the need to callInvoke
orBeginInvoke
lots of times.However, generally I would prefer a more "observer" based design here, with change-notification events (either
FooChanged
orINotifyPropertyChanged
) and event-handlers that cause the UI to reflect changes.你需要定时器控制而不是后台工作者
you need timer control instead of Background worker
您收到的异常可能是直接从您的BackgroundWorker 线程内的
_DoWork
调用Update()
(它正在修改主线程中的一个或多个表单)的结果。如果您要使用
BackgroundWorker
方法:.WorkerReportsProgress
属性设置为true
.ReportProgress()
方法来触发工作器的_ProgressChanged
事件处理程序。_ProgressChanged
事件处理程序可以安全地执行对表单的Update()
方法的调用如果您不再使用工作程序(特别是如果您的后台工作程序仅针对此循环而存在, ),那么我建议您采用Marc的建议标准事件处理程序。与添加外部循环或 Timer 控件相比,该路线将产生更少的处理器开销(无论当前可能或可能不是最小的)。
任一途径都应解决跨线程异常。
The exception you're receiving would be the result of calling
Update()
(which is modifying one or more forms in your primary thread ) directly from_DoWork
within your BackgroundWorker's thread.If you're going to use the
BackgroundWorker
method:.WorkerReportsProgress
property totrue
.ReportProgress()
method to trigger the worker's_ProgressChanged
event handler._ProgressChanged
event handler can then perform a call to your form'sUpdate()
method safelyIf you move away from using the worker (especially if your background worker solely exists for this loop), then I'd suggest you go with Marc's suggestion of standard event handlers. That route will yield less processor overhead (however minimal it currently may or may not be) than adding in your external loop or a
Timer
control.Either route should address the Cross-thread exception.