Моя цель:
Пользователь должен иметь возможность получить источник 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 или поймать событие внутри этой функции или функцию во второй форме, чтобы я мог вернуть это (чем код будет ждать сам по себе). Не знаю, как это сделать.
Ваше первое решение не будет работать, так как код еще продолжается, хотя я зарегистрирован на мероприятии. Первый класс нуждается в ответе через вызов второго класса, и поскольку я не знаю, когда это возвращаемое значение будет готово, я не могу вернуть что-то, кроме события для вызывающего, которое готово (если я хочу вернуть ценность в то время, я опаздываю). Вызывающий хочет получить ответ, и ему все равно, ждать ли он. – CappaMontana
Если вы действительно хотите заблокировать функцию, пока не получите ответ, вам нужно будет убедиться, что все ваши вызывающие абоненты не вызовут вашу функцию из диспетчера событий (например, в вашем примере button_click) напрямую. Пока выполняется обработчик кнопки, центральная очередь сообщений процесса блокируется, поэтому никакие другие события пользовательского интерфейса не могут быть созданы. не можете ли вы предоставить событие своему абоненту? – mihi
Да, я думал об этом, без особого успеха. Но однажды удалив код из диспетчера в form1 и form2 (просто сделал цикл while, который проверяет наличие некоторых данных вместо события documentLoaded), все сработало нормально! Tnx! – CappaMontana