【问题标题】:Can I wait for a webbrowser to finish navigating, using a for loop?我可以使用 for 循环等待网络浏览器完成导航吗?
【发布时间】:2017-01-24 16:42:15
【问题描述】:

我有一个 for 循环:

for (i = 0; i <= 21; i++)
{
  webB.Navigate(URL);
}

webB 是一个 webBrowser 控件,i 是一个 int。

我想等待浏览器完成导航。

我找到了this,但是:

  • 我不想使用任何 API 或插件
  • 我不能使用另一个void 函数,正如this answer 中所建议的那样

有没有办法在 for 循环中等待?

【问题讨论】:

  • 这个答案有什么不好? stackoverflow.com/a/956020/1714342
  • @wudzik cmets 声称它在运行时会占用大量 CPU 资源。
  • 每个没有完成事件(最好)的解决方案都会占用大量 CPU,也许可以尝试使用 Thread.Sleep?
  • @wudzik 哦,会吗?好的,谢谢你的建议。
  • 是的,你会陷入 for 循环,你会做一些事情(任何事情),它必须影响 CPU。

标签: c# webbrowser-control


【解决方案1】:

假设您在 WinFroms 应用程序中托管 WebBrowser,您可以使用 async/await 模式轻松高效地循环执行此操作。试试这个:

async Task DoNavigationAsync()
{
    TaskCompletionSource<bool> tcsNavigation = null;
    TaskCompletionSource<bool> tcsDocument = null;

    this.WB.Navigated += (s, e) =>
    {
        if (tcsNavigation.Task.IsCompleted)
            return;
        tcsNavigation.SetResult(true);
    };

    this.WB.DocumentCompleted += (s, e) =>
    {
        if (this.WB.ReadyState != WebBrowserReadyState.Complete)
            return;
        if (tcsDocument.Task.IsCompleted)
            return;
        tcsDocument.SetResult(true); 
    };

    for (var i = 0; i <= 21; i++)
    {
        tcsNavigation = new TaskCompletionSource<bool>();
        tcsDocument = new TaskCompletionSource<bool>();

        this.WB.Navigate("http://www.example.com?i=" + i.ToString());
        await tcsNavigation.Task;
        Debug.Print("Navigated: {0}", this.WB.Document.Url);
        // navigation completed, but the document may still be loading

        await tcsDocument.Task;
        Debug.Print("Loaded: {0}", this.WB.DocumentText);
        // the document has been fully loaded, you can access DOM here
    }
}

现在,重要的是要了解DoNavigationAsync 是异步执行的。以下是您如何从 Form_Load 调用它并处理它的完成:

void Form_Load(object sender, EventArgs e)
{
    var task = DoNavigationAsync();
    task.ContinueWith((t) =>
    {
        MessageBox.Show("Navigation done!");
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

我已经回答了一个类似的问题here

【讨论】:

  • 您能解释一下当 DocumentCompleted 处理程序中的那些 if 被命中时任务会发生什么吗? DocumentCompleted 处理程序是否被多次触发?
  • @lexeme 是的,它可能会被多次触发,例如对于带有iframes 的文档。我记得我在其他地方有更详细的介绍,如果有兴趣使用webbrowser-control 标签搜索我的其他答案。
  • 我尝试在我的 winforms 应用程序中实现静默打印。我以您的其他答案(stackoverflow.com/questions/19734151/…)为基础。然而,我总是让网络浏览器处于未初始化的就绪状态。可能是什么原因?
  • @lexeme,您的意思是该答案中的示例代码对您不起作用吗?
  • Noseratio,出于某种原因,是的,它不能按原样工作。我正在尝试打印 pdf 文档,可能与 ie 安全设置 idk 有关。 WebBrowser 保持未初始化就绪状态。
【解决方案2】:

您不必使用另一个void 函数。只需像这样使用lambda

webB.DocumentCompleted += (sender, e) =>
{
    // your post-load code goes here
};

【讨论】:

    【解决方案3】:

    正确的方法是使用事件。
    在你的循环中,你怎么知道导航已经完成?也许你不在循环中,但它只是完成了一半......

    另外,等待时循环称为Busy waiting,是CPU expensive

    为了在页面准备好时得到通知,同时保持 CPU 可用于其他东西,请按照@Jashaszun 的建议使用事件:

    void YourFunction()
    {
      //Do stuff...
      webB.DocumentCompleted += (sender, e) =>
      {
          //Code in here will be triggered when navigation is complete and document is ready
      };
      webB.Navigate(URL);
      //Do more stuff...
    }
    

    【讨论】:

      【解决方案4】:

      在 for 循环中使用这个 while 循环。

      while (webB.ReadyState != tagREADYSTATE.READYSTATE_COMPLETE)
                  {
                     Thread.Sleep(500);
                  }
      

      这会等到 WebBrowser 完全加载页面。

      【讨论】:

        【解决方案5】:

        要在线程中等待,您可以执行以下操作

         System.Threading.Thread.Sleep(2000); //waits 2 seconds
        

        很遗憾,它与导航完成时间没有关联。

        【讨论】:

        • 这将阻止导航,这需要 webbrowser 控件的托管线程及时泵送消息。
        【解决方案6】:

        尝试使用这样的任务:

        for (i = 0; i <= 21; i++)
        {
           Task taskA = Task.Factory.StartNew(() => webB.Navigate(URL));
           taskA.Wait();
        }
        

        希望我能帮上忙。

        【讨论】:

          【解决方案7】:
          Public Class Form1
          
              Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
          
                  WebBrowser1.Navigate("stackoverflow.com/")
          
              End Sub
          
              Private Sub WebBrowser1_DocumentCompleted(ByVal sender As System.Object, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
          
              ------yourcode------
          
              End Sub
          
          End Class
          

          【讨论】:

            猜你喜欢
            • 2010-10-27
            • 2018-10-14
            • 2014-07-19
            • 1970-01-01
            • 2022-01-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-08-09
            相关资源
            最近更新 更多