WebBrowser Control in a new thread

前端 未结 4 1440
执笔经年
执笔经年 2020-11-21 06:24

I have a list Uri\'s that I want \"clicked\" To achieve this I\"m trying to create a new web-browser control per Uri. I create a new thread per Uri. The problem I\'m having

4条回答
  •  你的背包
    2020-11-21 06:57

    Here is how to organize a message loop on a non-UI thread, to run asynchronous tasks like WebBrowser automation. It uses async/await to provide the convenient linear code flow and loads a set of web pages in a loop. The code is a ready-to-run console app which is partially based on this excellent post.

    Related answers:

    • https://stackoverflow.com/a/22262976/1768303
    • https://stackoverflow.com/a/21775343/1768303

    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 DoWorkAsync(object[] args)
            {
                Console.WriteLine("Start working.");
    
                using (var wb = new WebBrowser())
                {
                    wb.ScriptErrorsSuppressed = true;
    
                    TaskCompletionSource tcs = null;
                    WebBrowserDocumentCompletedEventHandler documentCompletedHandler = (s, e) =>
                        tcs.TrySetResult(true);
    
                    // navigate to each URL in the list
                    foreach (var url in args)
                    {
                        tcs = new TaskCompletionSource();
                        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 Run(Func> worker, params object[] args)
            {
                var tcs = new TaskCompletionSource();
    
                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();
                }
            }
        }
    }
    
        

    提交回复
    热议问题