winforms BackgroundWorker在DoWork之前完成

aelbi1ox  于 2022-11-17  发布在  其他
关注(0)|答案(3)|浏览(158)

我正在使用一个后台工作线程来处理文件的加载,以防止我的用户界面冻结,但是似乎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),但没有效果。

Edit2错误为NRE,因为设计尚未加载,我可以轻松修复此错误,但我更希望线程工作正常。

fdx2calv

fdx2calv1#

这里有很多小错误。考虑到我们可能没有看到真实的的代码,并且我们没有一个带有调用栈窗口的调试器来查看它实际上在哪里崩溃,它们中的任何一个都可能是一个因素。

  • 测试bw.IsBusy并在它为true时 * 不 * 启动worker是一个严重的错误。它在代码中永远不可能是busy,但如果它确实有可能为true,那么你的代码中就有一个严重的bug。因为你实际上 * 确实 * 订阅了一个繁忙的worker上的事件。现在RunWorkerCompleted事件处理程序将运行两次。
  • 使用Close()方法关闭对话框是不正确的。应该通过分配对话框的DialogResult属性来关闭对话框。这不是最严重的错误,但仍然是错误的。
  • 代码中存在竞争,辅助进程可能会在对话框显示之前完成。对话框只能在其本机窗口创建时关闭。换句话说,IsHandleCreated必须为true。您必须将其互锁以确保不会发生这种情况。订阅对话框的Load事件以启动辅助进程。
  • 你盲目地假设工作者会完成工作并产生结果。当它的DoWork方法因异常而死亡时,情况就不是这样了。异常被BackgroundWorker捕获,并作为e.Error属性传递给RunWorkerCompleted事件处理程序。你必须检查此属性,如果它不为空,就做一些合理的事情。

从评论中判断,我猜后一点是原因。您可以使用Debug + Exceptions来调试这个问题,勾选CLR异常的Thrown复选框。调试器现在将在抛出异常时停止,让您找出错误所在。

sulc1iza

sulc1iza2#

也许你的后台工作者实际上并没有花费太多的时间就完成了对话框的显示。我建议把后台工作者的初始化和启动代码转移到PleaseWait的Form_Load或Form_Shown

1qczuiv0

1qczuiv03#

如果在BackgroundWorker _DoWork事件中调用另一个异步函数,
喜欢;

private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
        somethingsToDoAsync();
        // somethingsToDoAsync() function is to ASYNC 
    }

_RunWorkerCompleted甚至在已完成_Dowork事件之前激发
将其他somethingsToDoAsync()函数更改为非异步。

相关问题