【发布时间】:2015-11-19 14:32:38
【问题描述】:
我有一个 WinForms 应用程序,并且我有一些代码需要在 UI 线程上运行。但是,await 之后的代码在不同的线程上运行。
protected override async void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
// This runs on the UI thread.
mainContainer.Controls.Clear();
var result = await DoSomethingAsync();
// This also needs to run on the UI thread, but it does not.
// Instead it throws an exception:
// "Cross-thread operation not valid: Control 'mainContainer' accessed from a thread other than the thread it was created on"
mainContainer.Controls.Add(new Control());
}
我也尝试过显式添加ConfigureAwait(true),但这并没有什么区别。我的理解是,如果我省略ConfigureAwait(false),那么继续应该在原始线程上运行。在某些情况下这是不正确的吗?
我还注意到,如果我在等待之前将控件添加到集合中,那么延续会神奇地在正确的线程上运行。
protected override async void OnHandleCreated(EventArgs e)
{
base.OnHandleCreated(e);
// This runs on the UI thread.
mainContainer.Controls.Add(new Control());
mainContainer.Controls.Clear();
var result = await DoSomethingAsync();
// This also runs on the UI thread now. Why?
mainContainer.Controls.Add(new Control());
}
我的问题是:
- 为什么会这样?
- 我如何说服 continuation 在 UI 线程上运行(最好不要像我那样添加和删除控件)?
作为参考,这里是DoSomethingAsync的重要部分。它使用 RestSharp 提交 HTTP 请求。
protected async Task DoSomethingAsync()
{
IRestRequest request = CreateRestRequest();
// Here I await the response from RestSharp.
// Client is an IRestClient instance.
// I have tried removing the ConfigureAwait(false) part, but it makes no difference.
var response = await Client.ExecuteTaskAsync(request).ConfigureAwait(false);
if (response.ResponseStatus == ResponseStatus.Error)
throw new Exception(response.ErrorMessage ?? "The request did not complete successfully.");
if (response.StatusCode >= HttpStatusCode.BadRequest)
throw new Exception("Server responded with an error: " + response.StatusCode);
// I also do some processing of the response here; omitted for brevity.
// There are no more awaits.
}
【问题讨论】:
-
为什么你认为它在不同的线程上运行?这段代码在哪里运行?事件处理程序?
-
我知道它在不同的线程上运行,因为等待之后的代码抛出异常:“跨线程操作无效:控件'mainContainer'从创建它的线程以外的线程访问"。
-
是的,代码在事件处理程序中运行。我会更新我的问题。
-
OnHandleCreated注册到哪个事件?因为winforms中的事件处理程序通常有2个参数。 -
HandleCreated事件肯定涉及到黑魔法。我改用Load事件,一切正常。无论如何,我不确定为什么要使用HandleCreated。 (我从别人那里继承了这段代码,而且很多很乱)。
标签: c# .net winforms async-await