无法在BackgroundWorker中管理线程

时间:2013-12-12 13:36:27

标签: c# .net wpf multithreading mvp

我的演示者课程中BackGroundWorker doWork方法存在问题。

我的第一个问题是为什么Thread.CurrentThread.Join()不起作用。 第一次点击该行后代码中断。我能做的只是设定一个计时器......

我的第二个问题是为什么CheckDocumentError()抛出“ 调用线程无法访问此对象,因为不同的线程拥有它 ”即使我正在调用它与Dispatcher。

我在这里缺少什么? 相关信息是设置Document属性和CheckDocumentError方法都更新UI。

private void worker_DoWork(object sender, DoWorkEventArgs e)
{

  foreach (KeyValuePair<string, Stream> pair in (Dictionary<string, Stream>)e.Argument)
  {

      Document = new Document(pair.Value);

      Thread.CurrentThread.Join(5000);

      Dispatcher.CurrentDispatcher.Invoke((Action)(() =>
      {
        CheckDocumentError(Document);
      }));

  }
}

3 个答案:

答案 0 :(得分:1)

如果要在后台线程中执行某些长时间运行的操作,则使用BackgroundWorker class,以便UI不会冻结。您应该手动与任何Thread对象进行交互,因为这些都是在幕后为您完成的。请尝试使用此代码:

private void worker_DoWork(object sender, DoWorkEventArgs e)
{    
    foreach (KeyValuePair<string, Stream> pair in (Dictionary<string, Stream>)e.Argument)
    {    
        Document = new Document(pair.Value);
        CheckDocumentError(Document);
    }
}

有关使用BackgroundWorker的更多帮助,请参阅MSDN上的链接页面。


更新&gt;&gt;&gt;

好的,我刚才注意到你问题中的一行:相关信息是设置Document属性和CheckDocumentError方法都更新UI。

无法DoWork方法更新用户界面,因为它在后台Thread上运行。您需要在长时间运行的部分中使用<{1}} 内部该方法才能使其正常工作。

答案 1 :(得分:1)

很难弄清楚你究竟想做什么。以下是如何从工作线程中以实际更新UI线程的方式启动UI更新,从而避免错误:

public partial class MainWindow : Window
{
    BackgroundWorker Worker;

    public MainWindow()
    {
        InitializeComponent();

        Worker = new BackgroundWorker();
        Worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        Worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
        Worker.RunWorkerAsync("param");
    }

    private void worker_DoWork(object sender, DoWorkEventArgs e)
    {
        tb.Dispatcher.Invoke((Action)(() =>
        {
            tb.Text = "doing work: " + (e.Argument as string);
        }));

        Thread.Sleep(5000);
    }

    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        tb.Dispatcher.Invoke((Action)(() =>
        {
            tb.Text = "finished work";
        }));
    }
}

请注意,由于我从后台线程更新UI,我不使用CurrentDispatcher,我使用负责拥有我正在更新的控件的线程的调度程序(tb是XAML文件中的TextBox)窗口)。

我不知道要替换你的CurrentThread.Join是什么,因为我不明白代码的那一部分。但是CurrentThread.Join肯定是错的,它基本上是一个线程上自我造成的死锁。

答案 2 :(得分:0)

您正在后台工作程序的线程中创建类型Document的实例。然后尝试从Dispatcher的线程访问它。这导致“调用线程无法访问此对象,因为另一个线程拥有它”错误,因为工作线程现在拥有类型Document的实例。在Dispatcher的线程中创建实例。