Backgroundworker/Control.BeginInvoke() 冻结 UI
我有一些代码执行 Windows svc (另一个进程)并同时更新 UI。这些调用使用 BeginInvoke
,如下所示:
Install.BeginInvoke((MethodInvoker) delegate { Install.Enabled = false; });
这是在 DoWork
事件处理程序中。然而,用户界面仍然冻结。我是否需要在某处调用 Application.DoEvents
(如果需要,在哪里?)?怎样才能消除冻结现象呢?
在按钮单击中,我有:
GetPrinterDto(DirectoriesTreeView.SelectedNode.Text);
InstallBackgoundWorker.RunWorkerAsync();
InstallBackgroundWorker
只是运行更新 UI 等的代码。
我想做的是调用 WCF 服务器(托管在 Windows 服务中 - 这很好),但是当它停止工作时,以异步方式更新进度条和具有任意值的标签。当我选择一个树节点时,所选树节点的事件处理程序被触发,这可能会导致速度减慢。我会尝试将其放入其自己的后台工作人员中。
I have some code which executes a windows svc (another process) and updates the UI at the same time. The calls use BeginInvoke
, like so:
Install.BeginInvoke((MethodInvoker) delegate { Install.Enabled = false; });
This is in the DoWork
event handler. However, the UI still freezes up. Do I need a call to Application.DoEvents
somewhere (if so, where?)? How can I eliminate the freezing?
In the button click, I have:
GetPrinterDto(DirectoriesTreeView.SelectedNode.Text);
InstallBackgoundWorker.RunWorkerAsync();
InstallBackgroundWorker
just runs the code which updates the UI etc.
What I am trying to do is call a WCF server (hosted in a windows service - this is fine), but while that is off doing its thing, update the progress bar and a label with arbitrary values in an async fashion. When I select a treenode, the event handler for selected treenode is f ired, which may cause some of the slowdown. I will try putting this in its own backgroundworker.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
虽然您当然可以在
DoWork
方法中调用更新 UI(这就是对BeginInvoke
的调用所做的事情),但您应该不,否则,您真的不需要BackgroundWorker
类。相反,您可以调用
ReportProgress
方法然后将触发ProgressChanged
事件。您可以在
ProgressChanged
事件的事件处理程序中调用Install.Enabled = false
。While you certainly could place the call to update the UI (which is what your call to
BeginInvoke
is doing) in theDoWork
method, you shouldn't, otherwise, you really wouldn't need theBackgroundWorker
class.Rather, you would call the
ReportProgress
method which would then fire theProgressChanged
event.It's in the event handler of the
ProgressChanged
event that you would make the call toInstall.Enabled = false
.该问题与
BeginInvoke
的使用没有直接关系。它可能与它被调用的次数有更多关系。您可以将ReportProgress
与ProgressChanged
事件结合使用,但假设您将所有BeginInvoke
调用替换为ReportProgress
那么您可能会遇到类似的问题,因为BackgroundWorker
将使用与BeginInvoke
/Invoke
相同的机制自动编组 UI 线程上的事件处理程序无论如何使用。我想说,快速解决方案是减少尝试更新 UI 的频率。就我个人而言,我认为使用
BeginInvoke
来更新 UI 的工作线程进度已经被过度使用了。同样,BackgroundWorker
类也推广了这种次优方法。通常最好让工作线程定期向共享数据结构发布更新信息,然后 UI 线程可以按照自己的计划获取更新信息(通常通过使用计时器进行轮询)。这有几个优点:不幸的是,BackgroundWorker 缺乏使用这种替代方法的必要机制。但是,只要您不太频繁地调用它,您应该可以使用
ReportProgress
。The problem is not directly related to the use of
BeginInvoke
. It probably has more to do with how much it is being called. You could useReportProgress
in conjunction with theProgressChanged
event, but assuming you replace all of yourBeginInvoke
calls withReportProgress
then you may wind up with similar problems becauseBackgroundWorker
will automatically marshal the event handlers on the UI thread using the same mechanisms thatBeginInvoke
/Invoke
are using anyway. I would say the quick solution is to reduce the frequency at which you are attempting to update the UI.Personally, I think the use of
BeginInvoke
to update the UI with worker thread progress is way overused. And in the same regard theBackgroundWorker
class promotes this suboptimal method as well. It is usually better to have the worker thread publish update information periodically to a shared data structure and then the UI thread can pick it up on its own schedule (usually by polling using aTimer
). This has several advantages:Control.Invoke\Control.BeginInvoke
imposes.It is unfortunate that
BackgroundWorker
lacks the necessary mechanisms for using this alternate approach. However, you should be okay with usingReportProgress
as long as you do not call it too frequently.