繁体   English   中英

Backgroundworker / Control.BeginInvoke()冻结UI

[英]Backgroundworker/Control.BeginInvoke() freezing UI

我有一些执行Windows svc(另一个过程)并同时更新UI的代码。 调用使用BeginInvoke ,如下所示:

Install.BeginInvoke((MethodInvoker) delegate { Install.Enabled = false; });

这在DoWork事件处理程序中。 但是,UI仍然冻结。 我是否需要在某个地方调用Application.DoEvents (如果需要,在哪里?)? 如何消除冻结?

在按钮中单击,我有:

GetPrinterDto(DirectoriesTreeView.SelectedNode.Text);

InstallBackgoundWorker.RunWorkerAsync();

InstallBackgroundWorker只运行更新UI等的代码。

我正在尝试做的是调用WCF服务器(托管在Windows服务中-很好),但是当这样做时,请以异步方式用任意值更新进度条和标签。 当我选择一个treenode时,将为选定的treenode填充事件处理程序,这可能会导致某些速度下降。 我将尝试将其放在自己的背景工作人员中。

您当然可以DoWork方法中发出调用以更新UI(这是对BeginInvoke的调用所做的事情),但您不应该这样做,否则,您实际上不需要BackgroundWorker类。

相反,您将调用ReportProgress方法 ,该方法将随后触发ProgressChanged事件

您将在ProgressChanged事件的事件处理程序中调用Install.Enabled = false

该问题与BeginInvoke的使用没有直接关系。 它可能与被调用的数量有关。 您可以将ReportProgressProgressChanged事件结合使用,但是假设您用ReportProgress替换了所有BeginInvoke调用,那么您可能会遇到类似的问题,因为BackgroundWorker将使用与BeginInvoke / Invoke相同的机制自动在UI线程上封送事件处理程序。无论如何都在使用。 我想说的快速解决方案是减少您尝试更新UI的频率。

就个人而言,我觉得用BeginInvoke更新与工作线程进步的UI是方式过度使用。 同样, BackgroundWorker类也促进了这种次优方法。 通常最好让工作线程定期将更新信息发布到共享的数据结构中,然后UI线程可以按自己的计划(通常通过使用Timer轮询)来获取它。 这有几个优点:

  • 它打破了Control.Invoke\\Control.BeginInvoke施加的UI和工作线程之间的紧密耦合。
  • 它将更新UI线程的责任放在了它应该属于的UI线程上。
  • UI线程可以指示更新的时间和频率。
  • UI消息泵不会像工作线程发起的封送处理技术那样被超限运行。
  • 辅助线程在继续下一步之前不必等待确认已执行更新(即,UI和辅助线程上的吞吐量都更高)。

不幸的是, BackgroundWorker缺少使用这种替代方法的必要机制。 但是,你应该没使用ReportProgress只要你不把它过于频繁。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM