Managing WebBrowser in a new thread

I have a Uri list that I want to click. To achieve this, I am trying to create a new Uri web browser control. I am creating a new thread for Uri. The problem I am facing is the end of the stream before the document is fully loaded, so I will never use the DocumentComplete event. How can I overcome this?

var item = new ParameterizedThreadStart(ClicIt.Click); var thread = new Thread(item) {Name = "ClickThread"}; thread.Start(uriItem); public static void Click(object o) { var url = ((UriItem)o); Console.WriteLine(@"Clicking: " + url.Link); var clicker = new WebBrowser { ScriptErrorsSuppressed = true }; clicker.DocumentCompleted += BrowseComplete; if (String.IsNullOrEmpty(url.Link)) return; if (url.Link.Equals("about:blank")) return; if (!url.Link.StartsWith("http://") && !url.Link.StartsWith("https://")) url.Link = "http://" + url.Link; clicker.Navigate(url.Link); } 
+73
multithreading c # browser
Nov 24 '10 at 17:41
source share
4 answers

You need to create an STA stream that pumps the message loop. This is the only hospitable environment for an ActiveX component such as WebBrowser. Otherwise, you will not receive the DocumentCompleted event. Code example:

 private void runBrowserThread(Uri url) { var th = new Thread(() => { var br = new WebBrowser(); br.DocumentCompleted += browser_DocumentCompleted; br.Navigate(url); Application.Run(); }); th.SetApartmentState(ApartmentState.STA); th.Start(); } void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) { var br = sender as WebBrowser; if (br.Url == e.Url) { Console.WriteLine("Natigated to {0}", e.Url); Application.ExitThread(); // Stops the thread } } 
+136
Nov 24 '10 at 21:09
source share

Here's how to organize a message loop in a thread other than the UI to run asynchronous tasks such as WebBrowser automation. It uses async/await to provide a convenient linear code flow and load a set of web pages in a loop. The code is a ready-to-run console application that is partially based on this excellent post .

Related answers:

  • stack overflow
  • stack overflow

 using System; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace ConsoleApplicationWebBrowser { // by Noseratio - https://stackoverflow.com/users/1768303/noseratio class Program { // Entry Point of the console app static void Main(string[] args) { try { // download each page and dump the content var task = MessageLoopWorker.Run(DoWorkAsync, "http://www.example.com", "http://www.example.net", "http://www.example.org"); task.Wait(); Console.WriteLine("DoWorkAsync completed."); } catch (Exception ex) { Console.WriteLine("DoWorkAsync failed: " + ex.Message); } Console.WriteLine("Press Enter to exit."); Console.ReadLine(); } // navigate WebBrowser to the list of urls in a loop static async Task<object> DoWorkAsync(object[] args) { Console.WriteLine("Start working."); using (var wb = new WebBrowser()) { wb.ScriptErrorsSuppressed = true; TaskCompletionSource<bool> tcs = null; WebBrowserDocumentCompletedEventHandler documentCompletedHandler = (s, e) => tcs.TrySetResult(true); // navigate to each URL in the list foreach (var url in args) { tcs = new TaskCompletionSource<bool>(); wb.DocumentCompleted += documentCompletedHandler; try { wb.Navigate(url.ToString()); // await for DocumentCompleted await tcs.Task; } finally { wb.DocumentCompleted -= documentCompletedHandler; } // the DOM is ready Console.WriteLine(url.ToString()); Console.WriteLine(wb.Document.Body.OuterHtml); } } Console.WriteLine("End working."); return null; } } // a helper class to start the message loop and execute an asynchronous task public static class MessageLoopWorker { public static async Task<object> Run(Func<object[], Task<object>> worker, params object[] args) { var tcs = new TaskCompletionSource<object>(); var thread = new Thread(() => { EventHandler idleHandler = null; idleHandler = async (s, e) => { // handle Application.Idle just once Application.Idle -= idleHandler; // return to the message loop await Task.Yield(); // and continue asynchronously // propogate the result or exception try { var result = await worker(args); tcs.SetResult(result); } catch (Exception ex) { tcs.SetException(ex); } // signal to exit the message loop // Application.Run will exit at this point Application.ExitThread(); }; // handle Application.Idle just once // to make sure we're inside the message loop // and SynchronizationContext has been correctly installed Application.Idle += idleHandler; Application.Run(); }); // set STA model for the new thread thread.SetApartmentState(ApartmentState.STA); // start the thread and await for the task thread.Start(); try { return await tcs.Task; } finally { thread.Join(); } } } } 
+22
Oct. 31 '13 at 23:43
source share

From my experience in the past, the web browser does not like to work outside the main flow of applications.

Try using httpwebrequests instead, you can set them as asynchronous and create a response handler to find out when it will succeed:

how-to-use-httpwebrequest-net-asynchronously

+3
Nov 24 '10 at 18:17
source share

A simple solution where multiple web browsers work simultaneously

  • Create a New Windows Forms Application
  • Put a button named button1
  • Place a text box named textBox1
  • Set text properties field: Multiline true and ScrollBars Both
  • Write the following button1 click handler:

     textBox1.Clear(); textBox1.AppendText(DateTime.Now.ToString() + Environment.NewLine); int completed_count = 0; int count = 10; for (int i = 0; i < count; i++) { int tmp = i; this.BeginInvoke(new Action(() => { var wb = new WebBrowser(); wb.ScriptErrorsSuppressed = true; wb.DocumentCompleted += (cur_sender, cur_e) => { var cur_wb = cur_sender as WebBrowser; if (cur_wb.Url == cur_e.Url) { textBox1.AppendText("Task " + tmp + ", navigated to " + cur_e.Url + Environment.NewLine); completed_count++; } }; wb.Navigate("https://stackoverflow.com/questions/4269800/webbrowser-control-in-a-new-thread"); } )); } while (completed_count != count) { Application.DoEvents(); Thread.Sleep(10); } textBox1.AppendText("All completed" + Environment.NewLine); 
0
Nov 01 '17 at 7:20
source share



All Articles