【问题标题】:Reactive Extensions waiting for event doesn't work first time around等待事件的响应式扩展第一次不起作用
【发布时间】:2016-03-31 20:42:29
【问题描述】:

我正在尝试创建一种方法,使用 WebBrowser 控件导航到网页并阻止执行,直到页面完全加载。

不幸的是,知道页面是否已完全加载并不是那么简单,仅基于事件NavigatingDocumentCompleted

它们一起组成一对:当Navigating 触发时,DocumentCompleted 将始终触发。

不幸的是,DocumentCompleted 会为每个加载的帧触发,因此它可能会在每页触发多次,这意味着看到以下序列并不罕见:Navigating - DocumentCompleted - Navigating - DocumentCompleted

因此,我将“页面完全加载”定义如下:如果DocumentCompleted 已触发,并且在此期间没有Navigating 再次触发一秒钟。

无论如何,我有以下作为我的 Rx 代码来尝试执行上述操作:

_pageLoaded = navigating.Select(_ => documentCompleted.Delay(TimeSpan.FromSeconds(1))).Switch().FirstAsync();

然后我在其他地方做一个await _pageLoaded,然后继续。

但是,由于某些奇怪的原因,这在第一次时不起作用。因此,当应用程序加载并且WebBrowser 导航到某个地方时,它会卡在await _pageLoaded 上,直到NavigatingDocumentCompleted 再次触发(即,我转到另一个URL - 或同一个)。

我做了一个快速项目只是为了测试这一点,事件 NavigatingDocumentCompleted 按预期触发,这是我的完整代码:

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");
    }
}

当有人在TextBox(我用google.com测试过)中输入一个URL并点击Button时的结果是:

  • 导航已触发
  • DocumentCompleted 已触发
  • ... ... 什么都没有

如果然后在WebBrowser 上单击一个链接,例如顶部的图片,则会发生以下情况:

  • 导航已触发
  • DocumentCompleted 已触发
  • 1 秒后 ... 完成加载

如果我再次点击Button 会发生什么:

  • 导航已触发
  • DocumentCompleted 已触发
  • 1 秒后 ... 完成加载
  • 显然,如果我之前没有点击页面中的任何链接,那么我会得到第二个 DoneLoading MessageBox

所以,我的问题很简单:第一次出现什么问题,我该如何解决?

编辑:我刚刚对一个不同的网站进行了测试,其中事件多次触发,并且在这些网站上运行良好。所以它实际上是网站,它只触发一次,而且它似乎只是第一次出现的问题。

【问题讨论】:

    标签: c# .net system.reactive


    【解决方案1】:

    问题是您在调用 Navigate 之后 等待 - 因此,取决于 Navigate 事件是否同步引发,Rx 永远不会看到第一个 Navigation 事件,或者它是一场比赛.

    试试这个:

        private async void button1_Click_1(object sender, EventArgs e)
        {
            var waiter = _pageLoaded.GetAwaiter();
            webBrowser.Navigate(textBox1.Text);
            await waiter;
            MessageBox.Show("DoneLoading");
        }
    

    顺便说一句,正是出于这个原因,它是异步代码中非常常见的模式,即开始等待事件完成并然后启动它 - 所以这是一个值得记住的好方法。

    【讨论】:

    • 这正是问题所在。这是因为将 Observables 视为事件,并认为 navigating = Observable.FromEventPattern(webBrowser, "Navigating"); 订阅了由它生成的任何事件,它只会将它们放在“流”中,等待我想要的任何东西随时接收。现在我知道了;)谢谢!
    • 您可能会发现这个答案也很有帮助:stackoverflow.com/questions/19895373/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多