异步/等待.NET的WebBrowser类的实现

Sea*_*n S 14 .net c# browser asynchronous async-await

长期读者,这里的第一次海报.

我的目标:在使用WebBrowser类时能够利用async/await.由于WebBrowser.Navigate(string url)是一个异步方法,因此在触发LoadComplete事件之前无法检查html文档.

到目前为止,这是我的(工作)代码:

public class AsyncWebBrowser
{
    protected WebBrowser m_WebBrowser;

    private ManualResetEvent m_MRE = new ManualResetEvent(false);

    public void SetBrowser(WebBrowser browser) {
        this.m_WebBrowser = browser;
        browser.LoadCompleted += new LoadCompletedEventHandler(WebBrowser_LoadCompleted);
    }

    public Task NavigateAsync(string url) {
        Navigate(url);

        return Task.Factory.StartNew((Action)(() => {
            m_MRE.WaitOne();
            m_MRE.Reset();
        }));
    }

    public void Navigate(string url) {
        m_WebBrowser.Navigate(new Uri(url));
    }

    void WebBrowser_LoadCompleted(object sender, NavigationEventArgs e) {
        m_MRE.Set();
    }
}
Run Code Online (Sandbox Code Playgroud)

这个上一课现在允许我使用以下内容:

public async void NavigateToGoogle() {
    await browser.NavigateAsync("www.google.com");
    //Do any necessary actions on google.com
}
Run Code Online (Sandbox Code Playgroud)

但是,我想知道是否有更有效/正确的方法来处理这个问题.具体来说,Task.Factory.CreateNew具有阻塞ManualResetEvent.感谢您的输入!

Eri*_*ert 12

首先,我认为这是学习async/await如何工作的一个很好的练习.

您似乎正在跳过箍,以使NavigateAsync返回任务.但它不必返回任务以便等待!该方法包含的await必须返回任务,但一个方法是awaitable不用返回任务; 它所要做的就是返回一些你可以调用GetAwaiter的类型.

你可以考虑实现这样的小类:

public struct WebBrowserAwaiter<T>
{
    public bool IsCompleted { get { ... } }
    public void OnCompleted(Action continuation) { ... }
    public T GetResult() { ... }
}
Run Code Online (Sandbox Code Playgroud)

并让NavigateAsync返回一些类型,您可以在其上调用返回WebBrowserAwaiter的GetAwaiter.当你可以创建自己的GetAwaiter方法时,不需要构建一个Task来获取它.

更一般地说,您可能想要考虑的事情,如果在第一次仍然导航时第二次调用NavigateAsync会发生什么?