【问题标题】:BackgroundWorker completes before DoWorkBackgroundWorker 在 DoWork 之前完成
【发布时间】:2013-05-24 09:09:35
【问题描述】:

我正在使用后台工作程序来处理文件的加载以阻止我的 ui 冻结但是似乎RunWorkerCompleted 在我的DoWork 事件完成之前完成(退出对话框时导致错误).. .有什么我做错了吗?我是否最好在一项任务中执行此操作?

public static <T> LoadDesign(string xmlPath)
{
    PleaseWait pw = new PleaseWait(xmlPath);
    pw.ShowDialog();
    return pw.design;
}


private PleaseWait(string xmlFile)
{
   InitializeComponent();
   bw = new BackgroundWorker();
   bw.WorkerSupportsCancellation = true;
   bw.DoWork += (s, e) =>
   {
      design = (Cast)DllCall containing XmlSerializer.Deserialize(...,xmlFile);
   };
   bw.RunWorkerCompleted += (s, e) => {
   //Exit please wait dialog
      this.Close(); 
   };
   if (!bw.IsBusy)
       bw.RunWorkerAsync();
}

我认为问题可能归结于我的后台工作人员正在调用 dll 并且没有等待响应。我尝试添加诸如while(design == null) 之类的检查无济于事..

编辑2 错误是 NRE,因为设计尚未加载,我可以轻松解决此问题,但宁愿让线程工作。

【问题讨论】:

  • 如果您想要答案,请提供有关核心代码的完整详细信息。这个(cast) DllCall 伪代码太多了。
  • @HenkHolterman - 我已经添加了方法,但我看不出它有多相关? (也在添加Using to dll
  • 你看到了什么错误?
  • 我对你如何称呼它更感兴趣。这是 DoWork 内部唯一相关的东西。
  • DoWork 或异步外部调用中是否有任何内容?你所展示的一切似乎都不是。否则我看不出“我的后台工作人员正在调用 dll 而不等待响应”有什么意义。

标签: c# winforms backgroundworker


【解决方案1】:

有很多小错误。鉴于我们可能没有查看真实代码,并且我们没有带有调用堆栈窗口的调试器来查看它实际崩溃的位置,因此其中任何一个都可能是一个因素。

  • 测试 bw.IsBusy 和 not 当它为真时启动工人是一个严重的错误。它永远不会忙于发布的代码,但如果它实际上可能是真的,那么你的代码中有一个令人讨厌的错误。因为您实际上确实订阅了忙碌工作人员的事件。现在 RunWorkerCompleted 事件处理程序将运行两次。

  • 使用 Close() 方法关闭对话框是不正确的。应通过分配其 DialogResult 属性来关闭对话框。不是最严重的错误,但仍然是错误的。

  • 代码中存在竞争,工作人员可以在对话框显示之前完成。对话框只能在创建其本机窗口时关闭。换句话说,IsHandleCreated 必须为真。您必须将其联锁以确保这永远不会发生。订阅对话框的 Load 事件以启动工作器。

  • 您盲目地假设工人将完成工作并产生结果。当它的 DoWork 方法死于异常时,情况就不是这样了。它被 BackgroundWorker 捕获并作为 e.Error 属性传递给 RunWorkerCompleted 事件处理程序。您必须检查此属性,如果它不为 null,请执行合理的操作。

从 cmets 来看,我猜是后者的原因。您可以使用 Debug + Exceptions 进行调试,勾选 CLR 异常的 Throw 复选框。现在,当抛出异常时,调试器将停止,以便您找出问题所在。

【讨论】:

  • 谢谢你,汉斯,你对我的盲目假设确实是正确的。我本来希望这个错误会被抛出?另外,您对我为什么要使用 DialogResult 有任何参考吗?我很感兴趣...
  • 肯定会抛出异常。并被捕获,因此可以将其传递给 RunWorkerCompleted 事件处理程序。这是有意设计的,如果BGW容易导致程序经常崩溃,那它就不会那么受欢迎。我会推荐任何有关 Winforms 编程的书来了解有关对话框的更多信息。有很多好的可供选择。或者直接点击按钮。
【解决方案2】:

在显示对话框之前,您的后台工作人员可能实际上并没有花费太多时间并完成。我建议将后台worker初始化和启动代码转移到PleaseWait的Form_Load或Form_Shown

【讨论】:

  • 我什至会把它转移到Shown,因为这是显示表单时触发的事件。 Load 可能在 Shown 之前被调用。
  • 我向 YK1 道歉,错误与表单无关。关闭,但我能理解为什么它看起来像这样,感谢您的回答。我会更新问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-29
  • 2012-03-27
相关资源
最近更新 更多