2009-08-09 8 views
3

Ich möchte 3 Threads erstellen, die jeweils das WebBroswear-Steuerelement ausführen. Also würde ich gerne den ThreadPool verwenden, um Dinge einfacher zu machen.MultiThreading WebBrowser-Steuerelement C# STA

for(int i = 0;i < 3;i++) 
{ 
    ThreadPool.QueueUserWorkItem(new WaitCallback(gotoWork), i)); 
} 
WaitAll(waitHandles); 

....../

void gotoWork(object o) 
{ 
    string url = String.Empty; 
    int num = (int)o; 
    switch(num) 
    { 
    case 0: 
     url = "google.com"; 
     break; 
    case 1: 
     url = "yahoo.com"; 
     break; 
    case 2: 
     url = "bing.com"; 
     break; 
    } 
    WebBrowser w = new WebBrower(); 
    w.Navigate(url); 
} 

aber ich erhalte eine Fehlermeldung, dass ich einen STA-Thread muß, die der Threadpool wird es nie sein. Bevor ich diese Methode ausprobiert habe, habe ich das versucht.

Thread[] threads = Thread[3]; 
for(int i = 0;i < 3;i++) 
{ 
    threads[i] = new Thread(new ParameterizedStart(gotoWork); 
    threads[i] = SetApartmentState(ApartmentState.STA); //whoo hoo 
    threads[i] = Start(); 
} 
for(int i = 0; i < 3;i++) 
{ 
    threads[i].Join(); 
} 

Und die WebBrowsern alle initialisiert und alles sieht gut aus, aber nur noch ein zwei tut eigentlich alles und es ist nie überhaupt consistant. Threading war so ein Albtraum. Kann jemand eine nette Alternative vorschlagen?

+0

Warum wollen Sie mehrere Seiten laden? Benötigen Sie einen WebBrowser oder würde ein HttpWebRequest funktionieren (z. B. müssen Sie die Seite sehen und/oder benötigen Sie JavaScript auf der Seite zum Ausführen)? Wenn Sie Web Crawling/Scraping durchführen möchten, gibt es effizientere Möglichkeiten. – Chad

Antwort

0
public sealed class SiteHelper : Form 
{ 
    public WebBrowser mBrowser = new WebBrowser(); 
    ManualResetEvent mStart; 
    public event CompletedCallback Completed; 
    public SiteHelper(ManualResetEvent start) 
    { 
     mBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(mBrowser_DocumentCompleted); 
     mStart = start; 
    } 
    void mBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) 
    { 
     // Generated completed event 
     Completed(mBrowser); 
    } 
    public void Navigate(string url) 
    { 
     // Start navigating 
     this.BeginInvoke(new Action(() => mBrowser.Navigate(url))); 
    } 
    public void Terminate() 
    { 
     // Shutdown form and message loop 
     this.Invoke(new Action(() => this.Close())); 
    } 
    protected override void SetVisibleCore(bool value) 
    { 
     if (!IsHandleCreated) 
     { 
      // First-time init, create handle and wait for message pump to run 
      this.CreateHandle(); 
      this.BeginInvoke(new Action(() => mStart.Set())); 
     } 
     // Keep form hidden 
     value = false; 
     base.SetVisibleCore(value); 
    } 
} 

Eine andere Klasse als

public abstract class SiteManager : IDisposable 
{ 
    private ManualResetEvent mStart; 
    private SiteHelper mSyncProvider; 
    public event CompletedCallback Completed; 

    public SiteManager() 
    { 
     // Start the thread, wait for it to initialize 
     mStart = new ManualResetEvent(false); 
     Thread t = new Thread(startPump); 
     t.SetApartmentState(ApartmentState.STA); 
     t.IsBackground = true; 
     t.Start(); 
     mStart.WaitOne(); 
    } 
    public void Dispose() 
    { 
     // Shutdown message loop and thread 
     mSyncProvider.Terminate(); 
    } 
    public void Navigate(string url) 
    { 
     // Start navigating to a URL 
     mSyncProvider.Navigate(url); 
    } 
    public void mSyncProvider_Completed(WebBrowser wb) 
    { 
     // Navigation completed, raise event 
      CompletedCallback handler = Completed; 
      if (handler != null) 
      { 
       handler(wb); 
      } 
    } 
    private void startPump() 
    { 
     // Start the message loop 
     mSyncProvider = new SiteHelper(mStart); 
     mSyncProvider.Completed += mSyncProvider_Completed; 
     Application.Run(mSyncProvider); 
    } 
} 


class Tester :SiteManager 
{ 
    public Tester() 
    { 
     SiteEventArgs ar = new SiteEventArgs("MeSite"); 

     base.Completed += new CompletedCallback(Tester_Completed); 
    } 

    void Tester_Completed(WebBrowser wb) 
    { 
     MessageBox.Show("Tester"); 
     if(wb.DocumentTitle == "Hi") 

     base.mSyncProvider_Completed(wb); 
    } 

    //protected override void mSyncProvider_Completed(WebBrowser wb) 
    //{ 
    // // MessageBox.Show("overload Tester"); 
    // //base.mSyncProvider_Completed(wb, ar); 
    //} 
} 

Auf dem Hauptformular:

private void button1_Click(object sender, EventArgs e) 
{ 
    //Tester pump = new Tester(); 
    //pump.Completed += new CompletedCallback(pump_Completed); 
    //pump.Navigate("www.cnn.com"); 

    Tester pump2 = new Tester(); 
    pump2.Completed += new CompletedCallback(pump_Completed); 
    pump2.Navigate("www.google.com"); 
} 
+0

wirft dies jeden Navigate in einen Thread und fährt mit der Ausführung fort? Wenn ja, muss für jeden Thread ein neues Tester-Objekt vorhanden sein? – xendi

0

Sie müssen Webbrowser-Steuerelement in irgendwo, um es funktionieren zu hosten (fügen Sie es zu einem Formular), zweitens sollten Sie Invoke() des Host-Steuerelement (oder einen ähnlichen Delegaten) wie Form.Invoke() zu interagieren mit WebBrowser-Steuerelement.

Keine Notwendigkeit, jetzt daran zu erinnern, aber ja, sollten Sie Ihre Themen sein STA

0

Sie diese Art von Klasse für Ihre Zwecke verwenden können WebBrowser-Steuerelement zu hosten:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 

namespace SomeNameSpace 
{ 
    public class WebForm : Form 
    { 
     public WebBrowser WebBrowser { get; set; } 

     public WebForm() 
     { 
      WebBrowser = new WebBrowser(); 
     } 
    } 
}