3

我正在使用后台工作人员来处理文件的加载以阻止我的 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)无济于事..

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

4

2 回答 2

7

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

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

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

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

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

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

于 2013-05-29T08:59:15.277 回答
1

在显示对话框之前,您的后台工作人员实际上可能不需要太多时间并完成。我建议将后台工作人员初始化并启动代码到PleaseWaitForm_Load 或 Form_Shown

于 2013-05-29T08:16:16.967 回答