C #Windows应用程序显示图片框,直到后台进程完成

时间:2017-11-24 06:26:12

标签: c# multithreading api async-await backgroundworker

我必须调用我的API并显示等待PictureBox(wait.gif),直到API完成并返回数据以将我的自定义控件绑定到tablepanellayout。

我不能在这里使用BackgroundWorker类,因为它在自定义控件中与我的子控件存在跨线程问题。

这里我只想做到这一点,是从主线程调用子线程,但直到它的执行完全显示PictureBox(wait.gif)并阻止其余代码执行。

有人可以建议我如何完成这项工作,或者请提供一些代码段。

1 个答案:

答案 0 :(得分:3)

有两篇文章帮助我理解async-await:

对于WinForms,您可以执行以下操作:

  • 如果您的数据查询功能具有异步版本来获取数据,请使用该功能。想想像SqlConnection.OpenAsync,Dapper.QueryAsync等
  • 这样的函数
  • 如果您的数据查询器没有异步版本,请使用Task.Run
  • 使其异步
  • 每个调用异步函数的函数都应该声明为async
  • 每个异步函数都返回Task而不是void Task<TResult>而不是TResult
  • 唯一的例外是事件处理程序:此函数返回void而不是Task
  • 在异步返回之前,应等待对其他异步函数的调用。

// 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等。