【问题标题】:WPF and background workerWPF 和后台工作者
【发布时间】:2011-11-17 20:05:23
【问题描述】:

我有一个 WPF 窗口,我想在后台线程中做一些工作..

当工作完成后,我想再做一次.. 就像一个循环之间的 UI 更新

我的代码:

private void InitializeBackgroundWorker()
        {
            m_stopCamera = false;
            m_worker = new BackgroundWorker();
            m_worker.DoWork += new DoWorkEventHandler(worker_DoWork);
            m_worker.RunWorkerCompleted += new     RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
            m_worker.WorkerSupportsCancellation = true;
        }

unsafe void worker_DoWork(object sender, DoWorkEventArgs e)
{
  // my work....
  e.Result = new MyResultClass(p1,p2..);
}

private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Cancelled)
                return;


            if (e.Error != null)
            {
                Logger.LogException(e.Error.ToString());
                Window_Closed(this, new EventArgs());
            }
            try
            {

                //UI work..
                DetectionResult result = e.Result as DetectionResult;
                if (result.Cancel == true)
                {
                    m_DetectedObjID = result.DetectionID;
                    // PlaySound();
                    audio_MediaEnded(this, new EventArgs());
                }
                else
                     ((BackgroundWorker)sender).RunWorkerAsync();

            }
            catch (Exception ex)
            {

                Logger.LogException(ex.ToString());
                Window_Closed(this,new EventArgs());
            }

        }

我知道这段代码不好,因为我遇到了线程地狱,无法正确调试它

例如..当代码运行时,我点击关闭按钮,我可以在事件中看到 工人一直很忙..导致无限循环..

 private void Window_Closed(object sender, EventArgs e)
        {

                if (m_worker.IsBusy)
                    m_worker.CancelAsync();

                while(m_worker.IsBusy);
                base.Close();
            }

        }

我做错了什么?谢谢

【问题讨论】:

  • 您能否说明如何处理worker_DoWork 方法中的挂起取消?
  • 我不处理它..仅在 RunWorkerCompleted 事件中
  • 在下面阅读我的答案。你需要自己设置e.Cancelledtrue

标签: c# wpf winforms multithreading


【解决方案1】:

AFAIK,您从未在 worker_DoWork 中将您的工作标记为已取消。该方法中的取消代码应如下所示:

if ((m_worker.CancellationPending == true))
{
   e.Cancel = true;
   return;
}

只有在那之后,您才会在完成处理程序中获得e.Cancelled==true,并且您的循环将停止。


如果您认为调用CancelAsync() 应该将Canceled 设置为true,那您就错了。这是来自 BackgroundWorker.CancelAsync() 的反编译代码:

public void CancelAsync()
{
  if (!this.WorkerSupportsCancellation)
    throw new InvalidOperationException(SR.GetString("BackgroundWorker_WorkerDoesntSupportCancellation"));
  this.cancellationPending = true;
}

如您所见,它只是将CancellationPending 设置为true,仅此而已。因此,您必须在worker_DoWork 中检查此属性,如第一个 sn-p 所示。

【讨论】:

  • 谢谢,我添加了它,但它没有解决我的问题..当窗口关闭时,我返回父窗口 window2.ShowDialog();.. 只有在窗口关闭后后台线程已停止。只有在我第二次调用 window2.ShowDialog() 之后才会发生崩溃。也许问题不在后台线程中,而在窗口导航中。你怎么看?
  • 如果是这样,这个崩溃问题可能完全不同,最好创建另一个问题。
  • 谢谢,你是对的。我不得不在窗口中处理一些没有自行处理的东西
【解决方案2】:

清线:

while(m_worker.IsBusy);//may be go to infinite loop

【讨论】:

  • 此行仅用于调试。发生的情况是我回到了前一个窗口但后台线程处于活动状态。
     Window window = new Window2(selectedTitle, m_selectedCamID); window.Owner = 这个;窗口.ShowDialog();  ShowDialog后调试器跳回window2的代码中的后台线程
  • @RedHat:很明显,无限循环在那一行。问题是 - 为什么?
  • CancelAsync() 请求取消挂起的后台操作,可能需要一点时间等待取消完成。
【解决方案3】:

如果你想在后台运行一些东西,你可以使用这个:

public void DoEvents()
{
    Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new Action(() =>
    {
        code;
        DoEvents();
    }));
}

代码将在 CPU 空闲时执行,因此不会影响主线程的性能。

【讨论】:

  • Dispatcher.Invoke 会影响性能,可能不是主线程而是工作线程,所以如果他想显示某种进度,他应该使用ReportProgress-Methode
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-25
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多