我必须调用我的API并显示等待PictureBox
(wait.gif),直到API完成并返回数据以将我的自定义控件绑定到tablepanellayout。
我不能在这里使用BackgroundWorker
类,因为它在自定义控件中与我的子控件存在跨线程问题。
这里我只想做到这一点,是从主线程调用子线程,但直到它的执行完全显示PictureBox
(wait.gif)并阻止其余代码执行。
有人可以建议我如何完成这项工作,或者请提供一些代码段。
答案 0 :(得分:3)
有两篇文章帮助我理解async-await:
对于WinForms,您可以执行以下操作:
Task
而不是void Task<TResult>
而不是TResult
。
// The event handler: make async. The only one that still returns void
async void OnButton1_clicked(object sender, ...)
{
// start fetching the data. Don't await yet, you'll have other things to do
Task<MyData> fetchDataTask = FetchData(...);
// meanwhile: show the user that you are busy:
this.ShowBusy(true); // show picture box?
// if needed do other things you can do before the data is fetched
this.ClearTable();
// once you have nothing meaningful to do, await for your data
MyData fetchedData = await fetchDataTask;
this.ProcessData(fetchedData);
// finished:
this.ShowBusy(false); // remove picture box
}
获取数据的函数的异步版本:
async Task<IQueryable<MyData>> FetchDataAsync(myParams)
{
using (SqlConnection dbConnection = new SqlConnection(...)
{
// open the connection, don't wait yet:
Task taskOpen = sqlCommand.OpenAsync();
// continue while opening:
using (var sqlCommand = new SqlCommand(...))
{
cmd.Parameters.AddWithValue(...);
// before executing the query: wait until OpenAsync finished:
await taskOpen;
// read the data. If nothing to do: await, otherwise use Task similar to Open
SqlDataReader dataReader = await cmd.ExecuteReaderAsync();
foreach (var row in dataReader)
{
... (some Await with GetFieldValueAsync
}
}
}
}
我不太熟悉在如此低级别上阅读SQL数据,我更喜欢实体框架和精巧,所以我的SqlReader中可能存在错误。也许有人可以纠正这个。你仍然可以得到要点。
如果你这样写,你的程序将非常敏感:每当程序必须等待某事时,控制权将被返回给函数的调用者,该函数可以继续处理,直到他遇到await,当给出控制权时回到调用者,继续处理等等。
请注意,如果您的程序没有等待某些内容,这将无法帮助您。如果您的主线程在几秒钟内进行了一些繁重的计算,那么您的程序将无法响应。考虑创建一个异步函数,为您使用Task.Run
执行此操作如果你有这样的编程,那么执行你的函数的所有线程将具有相同的上下文:它就好像只涉及UI线程一样。不需要互斥量,信号量,InvokeRequired
等。