在阻止UI线程的同时使用WebBrowser控件加载html

时间:2015-03-21 14:24:58

标签: c# winforms async-await webbrowser-control wait

我有一个.Net 4.5 WinForms应用程序,其中包含存储在数据库中的html。向用户显示页面列表。当他们单击一行时,页面将加载到WebBrowser中。我希望加载页面的过程与主UI线程同步(IOW,我不希望用户在加载页面之前能够执行任何其他操作)。加载html的代码是:

public class DocLoader
{
    private readonly WebBrowser browser;
    readonly TaskCompletionSource<object> loadedTCS = new TaskCompletionSource<object>();

    public DocLoader(WebBrowser browser)
    {
        this.browser = browser;
    }

    private void LoadedComplete(object sender, WebBrowserDocumentCompletedEventArgs e)
    {
        Debug.WriteLine("doc completed");
        loadedTCS.TrySetResult(null);
        browser.DocumentCompleted -= LoadedComplete;
    }

    public Task LoadDoc(string html)
    {
        browser.DocumentCompleted += LoadedComplete;
        browser.DocumentText = html;
        return loadedTCS.Task;
    }
}

调用这样的代码:

await new DocLoader(webBrowser1).LoadDoc(html);

将导致消息循环能够处理进程消息。这是不可取的。例如,用户可以在上一个完成加载之前单击列表中的另一个文档。

调用这样的代码:

new DocLoader(webBrowser1).LoadDoc(html).Wait();

结果是UI冻结并且文档从未加载,大概是因为DocumentCompleted事件不会在消息循环运行时触发。

是否还有完成此任务并使进程与UI线程同步?

1 个答案:

答案 0 :(得分:1)

WebBrowser要求其父线程抽取消息才能正常运行。在您的情况下,其父线程主UI线程,因此您无法使用Wait阻止它。一个hack可能是禁用整个UI,因为browser.DocumentText异步加载速度相当快:

Cursor.Current = Cursors.WaitCursor;
mainFrom.Enabled = false;
try
{
    await new DocLoader(webBrowser1).LoadDoc(html);
}
finally
{
    mainFrom.Enabled = true;
    Cursor.Current = Cursors.Default;
}

然而,这对用户不友好。 正确的方法将支持您的WebBrowser异步加载方案中的取消。如果用户单击另一行(前一行更新仍处于待处理状态),则需要取消挂起操作,并启动一个新操作。