WebBrowser控件:创建同步包装器

时间:2017-08-29 13:29:25

标签: wpf asynchronous webbrowser-control

试图绕过TaskCompletionSource。这是我写的同步(WebBrowser.Navigate()异步)下载网页并将其返回给调用者的小课程。我不确定我是否正确使用了TaskCompletionSource。有人可以说明我在这里缺少什么,或者这完全是一个过度设计的解决方案吗?

class PageDownloader
{
  private WebBrowser _WB = new WebBrowser();
  private TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();

  public PageDownloader()
  {
    _WB.LoadCompleted += _WB_LoadCompleted;
  }

  public string Download(string url)
  {
    _WB.Navigate(new Uri(url));

    tcs.Task.Wait();

    if (tcs.Task.IsCanceled || tcs.Task.IsFaulted)
      return null;
    else
      return (_WB.Document as mshtml.HTMLDocument).body.innerHTML;
  }

  private void _WB_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
  {
    var docTemp = _WB.Document as mshtml.HTMLDocument;
    foreach (mshtml.IHTMLImgElement imgElemt in docTemp.images)
      imgElemt.src = "";

    tcs.SetResult(true);
  }
}

2 个答案:

答案 0 :(得分:1)

我不确定async这里的含义,但WebBrowser.Navigate方法只返回void,无法使用async / await关键字等待在C#5中引入的。它会启动导航操作并立即返回,如果您想在导航实际完成后执行某些操作,则应订阅LoadCompleted事件处理程序。到目前为止一切都很好。

使用TaskCompletionSource<T>您实际上可以在班级Download中设置async方法,这样您实际上可以await结果。您可能还想捕获LoadCompleted事件处理程序中可能发生的任何异常:

class PageDownloader
{
    private WebBrowser _WB = new WebBrowser();
    private TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();

    public PageDownloader()
    {
        _WB.LoadCompleted += _WB_LoadCompleted;
    }

    public async Task<string> DownloadAsync(string url)
    {
        _WB.Navigate(new Uri(url));

        await tcs.Task.ConfigureAwait(false);

        if (tcs.Task.IsCanceled || tcs.Task.IsFaulted)
            return null;
        else
            return tcs.Task.Result;
    }

    private void _WB_LoadCompleted(object sender, System.Windows.Navigation.NavigationEventArgs e)
    {
        try
        {
            var docTemp = _WB.Document as mshtml.HTMLDocument;
            foreach (mshtml.IHTMLImgElement imgElemt in docTemp.images)
                imgElemt.src = "";

            tcs.SetResult(docTemp.body.innerHTML);
        }
        catch(Exception ex)
        {
            tcs.SetException(ex);
        }
    }
}

<强>用法:

PageDownloader downloader = new PageDownloader();
string html = await downloader.DownloadAsync("http://stackoverflow.com");
//or if you want to block synchronously
string html = downloader.DownloadAsync("http://stackoverflow.com").Result;

您也可以在班级中创建同步重载:

public string Download(string url)
{
    return DownloadAsync(url).Result;
}

答案 1 :(得分:0)

到目前为止,唯一有效的解决方案是使用Windows窗体WebBrowser控件,并使用以下代码:

public string Download(string url)
{
  bool flag = false;

  using (System.Windows.Forms.WebBrowser WB = new System.Windows.Forms.WebBrowser())
  {
    WB.DocumentCompleted += (sender, e) =>
    {
      var docTemp = WB.Document;
      foreach (HtmlElement imgElemt in docTemp.Images)
        imgElemt.SetAttribute("src", "");

      flag = true;
    };

    WB.Navigate(url);

    while (!flag)
      Application.DoEvents();

    return WB.Document.Body.InnerHtml;
  }
}

即使我只是在此代码中使用WPF WebBrowser控件替换WinForms版本,此代码也不会命中return行。

寻找更好的答案。