Question

I have problems with treads in BackGroundWorker doWork method on my presenter class.

My first question is why doesnt Thread.CurrentThread.Join() work. The code breaks after hitting the line first time. All i can do is set a timer...

My second question is why is CheckDocumentError() throwing "The calling thread cannot access this object because a different thread owns it" even if I am calling it with Dispatcher.

What am I missing here? The relevant information is that setting the Document attribute and CheckDocumentError method both update 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);
      }));

  }
}
Was it helpful?

Solution

It is hard to figure out what exactly you're trying to do. Here is how you can initiate the updating of the UI from your worker thread in a way that actually updates it on the UI thread, avoiding the error:

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";
        }));
    }
}

Notice that since I am updating the UI from the background thread, I don't use CurrentDispatcher, I use the dispatcher in charge of the thread that owns the control I am updating (tb is a TextBox in the XAML file of the window).

I am not sure what to replace your CurrentThread.Join with as I don't understand the point of that part of the code. But CurrentThread.Join is definitely wrong, it's basically a self-inflicted deadlock on a thread.

OTHER TIPS

The BackgroundWorker class is used when you want to perform some long running operation in a background thread so that the UI does not freeze. You are not supposed to interact with any Thread objects manually as this is all done 'behind the scenes' for you. Try this code instead:

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);
    }
}

For more help with using a BackgroundWorker, please refer to the linked page on MSDN.


UPDATE >>>

Ok, so I just noticed a line in your question: The relevant information is that setting the Document attribute and CheckDocumentError method both update UI.

You cannot update the UI from the DoWork method because it is running on a background Thread. You'll need to use your BackgroundWorker inside that method on just the long running part in order to make this work.

You are creating the instance of type Document in the background worker's thread. Then you try to access it from the Dispatcher's thread. That is causing the "The calling thread cannot access this object because a different thread owns it" error, since the worker thread now owns the instance of type Document. Create the instance in the Dispatcher's thread.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top