我有一个.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线程同步?
答案 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
异步加载方案中的取消。如果用户单击另一行(前一行更新仍处于待处理状态),则需要取消挂起操作,并启动一个新操作。