我正在尝试使用WebBrowser
控件创建一个方法,导航到网页并阻止执行,直到页面完全加载。
不幸的是,知道页面是否已完全加载并不是那么简单,只是基于事件Navigating
和DocumentCompleted
。
他们一起成对:当Navigating
开火时,DocumentCompleted
将会在此之后开火。
不幸的是DocumentCompleted
会为已加载的每一帧触发,因此每页可能会多次触发,这意味着看到以下序列并不罕见:Navigating
- DocumentCompleted
- {{ 1}} - Navigating
。
因此,我已将“页面已满载”定义如下:如果DocumentCompleted
已经触发,并且在此期间没有DocumentCompleted
再次触发,则已经过了一秒钟。
无论如何,我已经将以下内容作为我的Rx代码来尝试执行上述操作:
Navigating
然后在其他地方我做_pageLoaded = navigating.Select(_ => documentCompleted.Delay(TimeSpan.FromSeconds(1))).Switch().FirstAsync();
才继续。
然而,由于一些奇怪的原因,这在第一次不起作用。因此,当应用程序加载并且await _pageLoaded
在某处导航时,它会卡在WebBrowser
上,直到await _pageLoaded
和Navigating
再次触发(即,我转到另一个网址 - 或同一个)。
我做了一个快速项目,只是为了对此进行测试,事件DocumentCompleted
和Navigating
按预期启动,这是我的完整代码:
DocumentCompleted
有人在public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private IObservable<object> _pageLoaded;
private void Form1_Load(object sender, EventArgs e)
{
var navigating = Observable.FromEventPattern(webBrowser, "Navigating");
var documentCompleted = Observable.FromEventPattern(webBrowser, "DocumentCompleted");
_pageLoaded = navigating.Select(_ => documentCompleted.Delay(TimeSpan.FromSeconds(1))).Switch().FirstAsync();
}
private async void button1_Click(object sender, EventArgs e)
{
webBrowser.Navigate(textBox1.Text);
await _pageLoaded;
MessageBox.Show("DoneLoading");
}
private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
MessageBox.Show("DocumentCompleted fired");
}
private void webBrowser_Navigating(object sender, WebBrowserNavigatingEventArgs e)
{
MessageBox.Show("Navigating fired");
}
}
(我使用google.com测试过)中输入网址并点击TextBox
时的结果是:
如果然后在Button
点击链接,例如在顶部说图像,则会发生以下情况:
如果我再次点击WebBrowser
,则会发生以下情况:
Button
。所以,我的问题很简单:第一次它无法正常工作,我该如何解决?
编辑:我刚刚在一个不同的网站上进行了测试,其中的事件多次触发,并且在这些网站上运行正常。所以它实际上只是一次点火的网站,而且它似乎只是第一次出现问题。
答案 0 :(得分:4)
问题是你在之后等待你已经调用了Navigate - 所以根据是否同步引发Navigate事件,Rx从未看到第一个导航事件或者它是一个竞赛
试试这个:
private async void button1_Click_1(object sender, EventArgs e)
{
var waiter = _pageLoaded.GetAwaiter();
webBrowser.Navigate(textBox1.Text);
await waiter;
MessageBox.Show("DoneLoading");
}
顺便说一下,正因为如此,它在异步代码中的一个非常常见的模式是开始等待事件完成而然后启动它 - 所以这是一个值得记住的好事。