1

I have a button that navigates a web page. I was trying to put the navigation in a backgroundworker, but it doesn't navigate. If I put it in the click event of the button it works fine. I put a break point in the bgw_DoWork and it shows that it hits the point of creating a new wb object, however it skips the rest of the statements in the DoWork. I wanted to do this so that I can display a loading image while it is trying to get data from a web page. The webbrowser object is not part of the UI as the user doesn't need to see the scraping. It just downloads the information into an object and then later displays the object (outside of the BackgroundWorker).

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Reflection;
using System.ComponentModel;
using mshtml;

namespace WPF1
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {


        WebBrowser wb;
        private readonly BackgroundWorker bgw = new BackgroundWorker();

        public int i = 0;

        public MainWindow()
        {
            InitializeComponent();
            bgw.DoWork += bgw_DoWork;
            bgw.RunWorkerCompleted += bgw_RunWorkerCompleted;

       }

        private void GetSICData_Click(object sender, RoutedEventArgs e)
        {
            //mainTabControl.SelectedIndex = 1;

            //wb.Navigated += wb_Navigated;
            //wb.LoadCompleted += wb_LoadCompleted;
            //wb.Navigate("http://www.google.com");

            bgw.RunWorkerAsync();

        }

        private void bgw_DoWork(object sender, DoWorkEventArgs e)
        {
            wb = new WebBrowser();

            wb.Navigated += wb_Navigated;
            wb.LoadCompleted += wb_LoadCompleted;
            wb.Navigate("http://www.google.com");

        }

        private void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            MessageBox.Show("Background Complete");
        }

        void wb_LoadCompleted(object sender, NavigationEventArgs e)
        {

            HTMLDocument doc = (HTMLDocument)wb.Document;
            doc.getElementById("ctl03_TextBox1").innerText = "2334882";

            wb.LoadCompleted -= wb_LoadCompleted;
            wb.LoadCompleted += wb_LoadCompleted_2;

            doc.getElementById("ImageButton1").click();

        }

        void wb_LoadCompleted_2(object sender, NavigationEventArgs e)
        {
            MessageBox.Show("It Worked!");
        }

        void wb_Navigated(object sender, NavigationEventArgs e)
        {

        }

    }
}
user3175176
  • 171
  • 1
  • 2
  • 14
  • 4
    You cannot control UI elements in a background thread – Shawn Kendrot Jan 13 '14 at 21:44
  • Is there a way to create a webbrowser object that is not part of the UI? – user3175176 Jan 13 '14 at 22:03
  • 2
    @user3175176 You probably shouldn't be using a WebBrowser if you don't want to display it as a part of UI, instead you should probably be using other classes entirely that are designed to download a website's contents without displaying them. – Servy Jan 13 '14 at 22:04
  • Thank you servy. I will look into that. I just figured that since the WebBrowser was built in that it would be easiest to use. Do you have any suggestions on what other classes can be used? – user3175176 Jan 13 '14 at 22:05
  • @EricJ., while this seems very similar to your 'possible duplicate' post at first, the question author's question and comments seem to say that they actually just want to download a web page in the background. So this question, although worded somewhat poorly, is about a different subject. Perhaps the question author could edit to make it clearer and you could remove your close vote? – Sheridan Jan 13 '14 at 23:16
  • @Sheridan: Good catch finding the real question in what seemed like another thread marshalling question. – Eric J. Jan 14 '14 at 15:03

3 Answers3

4

It sounds like what you really want is the WebClient Class. You can use a number of its methods to download either the whole web page as a file, or as a string. The best part is that you can also do this asynchronously, so it will all happen on a background thread automatically.

When using these asynchronous methods, you need to handle the relevant Download...Completed event to retrieve the results. From the DownloadStringCompletedEventHandler Delegate page on MSDN:

public static void DownloadStringInBackground2 (string address)
{
    WebClient client = new WebClient ();
    Uri uri = new Uri(address);

    // Specify that the DownloadStringCallback2 method gets called 
    // when the download completes.
    client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(
DownloadStringCallback2);
    client.DownloadStringAsync (uri);
}

private static void DownloadStringCallback2 (Object sender, 
DownloadStringCompletedEventArgs e)
{
    // If the request was not canceled and did not throw 
    // an exception, display the resource. 
    if (!e.Cancelled && e.Error == null)
    {
        string textString = (string)e.Result;

        Console.WriteLine (textString);
    }
}

Take a look at the WebClient.DownloadStringAsync Method and WebClient.DownloadFileAsync Method pages on the MSDN website for more information.

Sheridan
  • 68,826
  • 24
  • 143
  • 183
0

You cannot create a UI control on a background thread and in this case you don't need to because all of the WebBrowser methods you need are executed asynchronously anyway...

WebBrowser.Navigate

Navigate asynchronously to the document at the specified Uri.

BTW, don't forget to use Navigate method after the WebBrowser control is loaded so either use IsLoaded to check or call Navigate from Loaded event...

Dean Kuga
  • 11,878
  • 8
  • 54
  • 108
-1

Some of the UI operations requires being invoked on the UI thread. Try

    private void bgw_DoWork(object sender, DoWorkEventArgs e)
    {
        wb.Navigated += wb_Navigated;
        wb.LoadCompleted += wb_LoadCompleted;

        wb.Dispatcher.Invoke(() =>
        {

            wb.Navigate("http://www.google.com");
        });
    }
Fangliang Xue
  • 364
  • 2
  • 16
  • There's no point in using a BGW in the first place if you do nothing but invoke to the UI thread within it. – Servy Jan 13 '14 at 22:00
  • Yeah, you are right. I just trying to make a point but should have pay more attention on the sample code. WebClient sounds like a better idea anyway. – Fangliang Xue Jan 14 '14 at 01:44