Warten auf Ereignis innerhalb einer Funktion
Mein Ziel:
Benutzer sollten in der Lage sein, um die html-Quelle einer Seite, die beim klicken auf eine Schaltfläche. Dieses Ereignis öffnet sich ein neues Formular mit einer geckoWebBrowser Komponente und navigiert zu einer url.
Sobald dies erledigt ist, feuert Sie einen documentCompleted-Ereignis.
Dann kann ich beginnen mit dem laden des DOM.
Das problem:
Während das laden der Seite braucht Zeit, ich muss warten, bis in der zweiten form-Klasse des DOM (oder nur den Wert von a div) ist geladen. Das ist genau das problem! Jede warte-oder loop-stucks der zweiten form (geckoBrowser), so kann ich nicht den Wert.
Dies ist der code des ersten Formulars:
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");
//}
}
}
Dies ist das zweite:
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);
}
}
}
}
Nun sollte ich in der Lage, einfach warten, bis ich eine Antwort bekommen in der button1_Click-Funktion oder nehmen Sie die Veranstaltung innerhalb dieser Funktion oder eine Funktion auf der zweiten form so kann ich Sie zurückgeben (als die code warten, der von sich selbst). Weiß nicht, wie Sie dies tun.
InformationsquelleAutor CappaMontana | 2009-11-25
Du musst angemeldet sein, um einen Kommentar abzugeben.
Die grundlegende Idee wäre, teilen Sie die Funktion in zwei Teile, setzen Sie den code, der ausgeführt werden soll, nachdem das Ereignis tritt in einem anonymen Delegaten:
Statt
tun Sie
Die einzige alternative die ich kenne ist, die gesamte Verarbeitung in einem zweiten thread und Monitor verwenden.Warten und Überwachen.Impuls zu sagen, der zweite thread, wenn er fortgesetzt werden kann. Dies erzeugt mehr Aufwand und wird in der Regel langsamer, obwohl. Es könnte eine gute Idee sein, wenn Sie müssen warten, für 10 Veranstaltungen und fortsetzen, wenn der Letzte ankommt (und man weiß nicht die Reihenfolge), aber nicht in diesem einfachen Fall erläutert.
Wenn Sie wirklich wollen, zu blockieren, in Ihrer Funktion, bis Sie eine Antwort bekommen, die Sie haben, um sicherzustellen, dass alle Ihre Anrufer nicht anrufen, Ihre Funktion aus einem Ereignis-dispatcher (wie in deinem Beispiel button_click) direkt. Solange ein button-handler ausgeführt wird, das zentrale Nachrichten-queue der Prozess wird blockiert, so dass keine anderen UI-Ereignisse erstellt werden können. können Sie nicht, geben Sie ein Ereignis, um Ihre Anrufer?
Ja, ich dachte über, dass, ohne wirklich Erfolg. Aber einmal entfernen Sie den code aus dem dispatcher in form1 und form2 (nur aus einer while-Schleife, die prüft auf vorhanden von einige Daten anstelle der documentLoaded event) alles geklappt hat! Tnx!
InformationsquelleAutor mihi