4

The only reason I chose to use a BackgroundWorker for the application I am currently developing is to move the lengthy time-consuming browsing via a WebBrowser away from the UI thread.

But isn't WebBrowser.Navigate() accessing the UI?

In other words, I went through all this effort, only to land in the same spot (or worse! because I have no idea what side-effects could a non-UI thread have when accessing UI controls).

I am pretty sure I am not the first one wanting to implement something like this, so my question is: What is an acceptable way to solve this problem? i.e. To WebBrowser.Navigate() from BackgroundWorker?

ateiob
  • 9,016
  • 10
  • 44
  • 55
  • `Navigate()` is not a blocking call. – SLaks Oct 24 '12 at 20:09
  • @SLaks What do you mean? I can actually see that while a website's page is being (slowly) loaded, the form's buttons & UI are unresponsive. And this is with `WebBrowser.Navigate()` being called from `worker_DoWork(object sender, DoWorkEventArgs e)`. – ateiob Oct 24 '12 at 20:10
  • @ateiob The remarks of the BackgroundWorker specifically say 'You must be careful not to manipulate any user-interface objects in your DoWork event handler. Instead, communicate to the user interface through the BackgroundWorker events.' – RobH Oct 24 '12 at 21:12
  • 2
    @Munchies That's exactly what I am asking in my OP: **How** to *"communicate to the user interface through the BackgroundWorker events"*? – ateiob Oct 24 '12 at 21:16
  • @ateiob well what do you want to happen? You'd normally interact with the UI in your ProgressChanged or RunWorkerCompleted event handlers. I don't know why you're trying to use a background worker for a single method call. – RobH Oct 25 '12 at 08:07

1 Answers1

4

Navigate() is not a blocking call (see the first line in the MSDN docs), but it does update UI, and so it needs to be called from the UI thread.

You have a couple of options:

  1. Marshal the Navigate() call onto the UI thread from the BackgroundWorker via an Invoke call
  2. Don't use a BackgroundWorker - just make the call to Navigate() from your UI (e.g. a button click event handler) and listen for the WebBrowser DocumentCompleted event.

For an example of 1 - see https://stackoverflow.com/a/1862639/517244

Here's a code sample for 2:

public partial class MainForm : Form
{
    public MainForm()
    {
        InitializeComponent();
    }

    private void _goButton_Click(object sender, EventArgs e)
    {
        _webBrowser.Navigate("http://google.com/");
        // Non-blocking call - method will return immediately
        // and page will load in background
    }

    private void _webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        // Navigation complete, we can now process the document
        string html = _webBrowser.Document.Body.InnerHtml;
        // If the processing is time-consuming, then you could spin
        // off a BackgroundWorker here
    }
}
Community
  • 1
  • 1
Ross McNab
  • 11,337
  • 3
  • 36
  • 34