2009-11-25 60 views
1

我的目标:
用户应该能够得到一个页面的HTML源,当点击一个按钮。该事件使用geckoWebBrowser组件打开一个新窗体并导航到给定的URL。 一旦完成,它将触发一个documentCompleted事件。 然后我可以开始加载DOM。等待功能内的事件

问题:
虽然网页的加载需要时间,我都在DOM(或一个div只是值)加载第二个窗体类等待,直到。这正是问题所在!每一个等待或循环都会捕获第二种形式(geckoBrowser),所以我无法获得价值。

这是第一种形式的代码:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Threading; 

namespace mozillaFirefox2 
{ 
public partial class Form1 : Form 
{ 

    string source = ""; 

    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     //BackgroundWorker bw = new BackgroundWorker(); 
     //bw.DoWork += new DoWorkEventHandler(bw_DoWork); 

     Browser br = new Browser(); 
     //object parameters = br; 
     //bw.RunWorkerAsync(parameters); 
     br.navigate("http://www.google.com/#hl=en&q=superman&aq=f&aqi=&oq=&fp=1&cad=b"); 

     Thread th = new Thread(delegate() { this.dw(br); });    
     th.Start(); 
     th.Join(2000); 

     richTextBox1.AppendText(br.GetSource + "\n");    
    } 

    private void dw(Browser br) 
    { 
     while (br.workDone == false) 
     { 
      //donothing 
     } 
     source = br.GetSource; 
    } 

    //void bw_DoWork(object sender, DoWorkEventArgs e) 
    //{ 
    // Browser br = (Browser)e.Argument; 
    // while (br.workDone == false) 
    // { 
    //  //donothing 
    // } 
    // richTextBox1.AppendText(br.GetSource + "\n"); 
    //} 
} 
} 

这是第二次:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Threading; 

namespace mozillaFirefox2 
{ 
//Declare a delegate who points to a function/signature 
public delegate void GotDataEventHandler(object sender, EventArgs e); 


class Browser : Form 
{ 
    public event GotDataEventHandler GotData; 

    private System.ComponentModel.IContainer components = null; 

    protected override void Dispose(bool disposing) 
    { 
     if (disposing && (components != null)) 
     { 
      components.Dispose(); 
     } 
     base.Dispose(disposing); 
    } 

    #region Windows Form Designer generated code 

    /// <summary> 
    /// Required method for Designer support - do not modify 
    /// the contents of this method with the code editor. 
    /// </summary> 
    private void InitializeComponent() 
    { 
     this.geckoWebBrowser1 = new Skybound.Gecko.GeckoWebBrowser(); 
     this.SuspendLayout(); 

     // 
     // geckoWebBrowser1 
     // 
     this.geckoWebBrowser1.Location = new System.Drawing.Point(14, 4); 
     this.geckoWebBrowser1.Name = "geckoWebBrowser1"; 
     this.geckoWebBrowser1.Size = new System.Drawing.Size(261, 67); 
     this.geckoWebBrowser1.TabIndex = 2; 
     this.geckoWebBrowser1.DocumentCompleted += new EventHandler(geckoWebBrowser1_DocumentCompleted); 
     //Never forget this. Otherwise this error is raised "Cannot call Navigate() before the window handle is created" 
     this.geckoWebBrowser1.CreateControl(); 
     // 
     // Form1 
     // 
     this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 
     this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 
     this.ClientSize = new System.Drawing.Size(788, 577); 
     this.Controls.Add(this.geckoWebBrowser1); 
     this.Name = "Form1"; 
     this.Text = "Form1"; 
     this.ResumeLayout(false);    

    } 

    #endregion 

    public Skybound.Gecko.GeckoWebBrowser geckoWebBrowser1; 

    public string source = ""; 

    public bool workDone = false; 

    public bool navCall = false; 

    [STAThread] 
    public Browser() 
    { 
     Skybound.Gecko.Xpcom.Initialize(@"C:\Program Files\Mozilla-Gecko ActiveX WebBrowserControl\xulrunner-1.9.1.2.en-US.win32\xulrunner"); 
     Skybound.Gecko.GeckoPreferences.User["general.useragent.override"] = "Mozilla/5.0 (Windows; U; Windows NT 6.0; nl; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 (.NET CLR 3.5.30729)"; 
     this.InitializeComponent();       
     this.Show(); 
    } 


    public delegate void NavigationHandler(string url); 
    public void navigate(string url) 
    { 
     if (this.InvokeRequired) 
     { 
      object[] parameters = { url }; 
      this.geckoWebBrowser1.Invoke(new NavigationHandler(navigate), parameters); 
     } 
     else 
     { 
      navCall = true; 
      this.geckoWebBrowser1.Navigate(url); 
     } 
    } 

    public string GetSource 
    { 
     get { return source; } 
    } 

    public string getSource() 
    { 
     return source; 
    } 

    public void geckoWebBrowser1_DocumentCompleted(object sender, EventArgs e) 
    { 
     if(navCall == true){ 
      source = this.geckoWebBrowser1.Document.GetElementById("res").InnerHtml.ToString(); 
      workDone = true; 
      navCall = false; 

      // 
      GotDataEventHandler gd; 
      lock (this) 
      { 
       gd = GotData; 
      } 
      if (gd != null)gd(this, EventArgs.Empty); 

     } 
    } 
} 
} 

现在我应该可以,等我拿到的button1_Click函数内答复或在这个函数中捕获事件或者在第二个表单上捕获一个函数,这样我就可以返回它(比代码本身会等待)。不知道如何做到这一点。

回答

1

的基本思想是将功能分成两个部分,把事件中的匿名委托发生后,应当运行的代码:

你做

而不是

void doStuff() { 
    firstPart(); 
    waitEvent(); 
    secondPart(); 
} 

void doStuff() { 
    firstPart(); 
    some.Event += delegate { 
     secondPart(); 
    } 
} 

我知道的唯一选择是将整个处理放到第二个线程中,并使用Monitor.Wait和Monitor.Pulse告诉第二个线程何时可以你继续。尽管如此,这会产生更多的开销并且通常会变慢。这可能是一个好主意,如果您需要等待10个事件并在最后一个到达时继续(而您不知道该顺序),但不是在上面概述的简单情况下。

+0

您的第一个解决方案将无法正常工作,即使我已注册一个事件,仍会继续执行代码。第一类需要通过调用第二类的答案,因为我不知道什么时候它的返回值已经准备好了,我不能将除事件之外的东西返回给调用者,这已经准备好了(如果我想返回一个当时的价值,我要迟到了)。 来电者想要一个答案,并不在乎它是否必须等待。 – CappaMontana 2009-11-26 12:50:19

+0

如果你真的想阻止你的函数,直到你得到答案,你将不得不确保所有的调用者不会直接从事件调度器(如你的例子button_click)调用你的函数。只要按钮处理程序运行,进程的中央消​​息队列就会被阻塞,因此不会创建其他UI事件。你能不能为你的来电者提供一个事件? – mihi 2009-11-26 23:28:28

+0

是的,我想过,没有真正成功。但是一旦从form1和form2中的调度程序中删除代码(只是做了一个while循环来检查一些数据而不是documentLoaded事件),一切正常! Tnx! – CappaMontana 2009-11-27 13:34:40