WPF和后台工作者

时间:2011-11-17 20:05:23

标签: c# wpf winforms multithreading

我有一个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();
            }

        }

我做错了什么?感谢

3 个答案:

答案 0 :(得分:1)

明确界限:

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

答案 1 :(得分: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中检查此属性,如第一个代码段所示。

答案 2 :(得分:0)

如果您想在后台运行某些内容,可以使用:

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

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