2

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

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

这是在DoWork事件处理程序中。但是,用户界面仍然冻结。我需要打电话到Application.DoEvents某个地方吗(如果需要,在哪里?)?我怎样才能消除冻结?

在按钮单击中,我有:

GetPrinterDto(DirectoriesTreeView.SelectedNode.Text);

InstallBackgoundWorker.RunWorkerAsync();

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

我想要做的是调用 WCF 服务器(托管在 Windows 服务中 - 这很好),但是当它关​​闭时,以异步方式更新进度条和带有任意值的标签。当我选择一个树节点时,所选树节点的事件处理程序被触发,这可能会导致一些减速。我会尝试把它放在它自己的后台工作人员中。

4

2 回答 2

4

虽然您当然可以在方法中调用更新 UI(这是您的调用BeginInvoke正在执行的操作),但DoWork您不应该这样做,否则,您真的不需要BackgroundWorker该类。

相反,您将调用将触发事件的ReportProgress方法ProgressChanged

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

于 2011-05-09T16:41:42.877 回答
1

问题与使用没有直接关系BeginInvoke。它可能与它被调用多少有关。您可以ReportProgressProgressChanged事件一起使用,但假设您将所有BeginInvoke调用替换为ReportProgressthen 您可能会遇到类似的问题,因为将使用/无论如何都使用BackgroundWorker的相同机制自动编组 UI 线程上的事件处理程序。我想说快速的解决方案是减少您尝试更新 UI 的频率。BeginInvokeInvoke

就个人而言,我认为使用BeginInvoke工作线程进度更新 UI 被过度使用了。同样,该BackgroundWorker课程也提倡这种次优方法。通常最好让工作线程定期将更新信息发布到共享数据结构,然后 UI 线程可以按照自己的时间表获取它(通常通过使用轮询Timer)。这有几个优点:

  • 它打破了 UI 和工作线程之间的紧密耦合Control.Invoke\Control.BeginInvoke
  • 它将更新 UI 线程的责任放在它应该属于的 UI 线程上。
  • UI 线程可以决定更新的时间和频率。
  • 不存在 UI 消息泵溢出的风险,就像工作线程启动的编组技术那样。
  • 工作线程不必等待确认更新已执行,然后再继续执行后续步骤(即,您可以在 UI 和工作线程上获得更多吞吐量)。

不幸的是,BackgroundWorker缺乏使用这种替代方法的必要机制。但是,只要您不经常调用它,您应该可以使用它。ReportProgress

于 2011-05-09T18:07:10.833 回答