c# – 使用await和async运行long方法时释放UI线程

我开始探索异步并从c#5.0等待关键字,所以我使用
winforms进行了一些测试,但现在我陷入了困境:

我的观点是从数据库运行查询,而查询未完成,我想在表单上显示加载gif.

这是查询数据库的方法:

public static async Task<List<string>> GetItensFromDatabase()
    {
        List<string> names = new List<string>();

        using (ServerConn)
        {
            ServerConn.Open();
            SqlCommand cmd = new SqlCommand("Select * From Names", ServerConn);

            var ds = new DataSet();
            var adapter = new SqlDataAdapter(cmd);
            adapter.Fill(ds); // this call lasts about 1 minute

            foreach (DataRow dr in ds.Tables[0].Rows)
            {
                names.Add(dr["Name"].ToString());
            }
        }
        return names;
    }

我在这里称这种方法:

private async void button1_Click(object sender, EventArgs e)
    {
        List<string> itens = null;
        itens = await AsyncMethods.GetItensFromDatabase(); // I want that the form dont be stuck here

        ShowItensInListView(itens);
    }

现在我在旋转的窗体上有一个无所不在的加载图像gif,直到调用方法GetItensFromDatabase,当方法运行时,gif停止,当方法完成gif开始再次旋转时.

那么,有些方法可以在GetItensFromDatabase方法运行时保持gif旋转吗?

最佳答案 您可以在异步方法中使用await关键字,但由于没有等待操作,您应该使用TaskFactory在方法中显式创建一个Task:

public static Task<List<string>> GetItensFromDatabase()
{
    return Task.Factory.StartNew<List<string>>(() => 
    { 
        List<string> names = new List<string>();

        using (ServerConn)
        {
            ServerConn.Open();
            SqlCommand cmd = new SqlCommand("Select * From Names", ServerConn);

            var ds = new DataSet();
            var adapter = new SqlDataAdapter(cmd);
            adapter.Fill(ds); // this call lasts about 1 minute

            foreach (DataRow dr in ds.Tables[0].Rows)
            {
                names.Add(dr["Name"].ToString());
            }
        }
        return names;
    });
}

编辑:正如@mmarques所指出的,另一个(更好的)解决方案是使用SqlDataReader而不是SqlDataAdapter.原因是SqlDataReader具有可用的异步方法 – 这意味着您不需要使用TaskFactory来阻塞线程池中的新线程,并且您可以使用async和await.

public static async Task<List<string>> GetItensFromDatabase()
{
    List<string> names = new List<string>();

    using (ServerConn)
    {
        using (SqlCommand cmd = new SqlCommand("Select * From Names", ServerConn))
        {
            ServerConn.Open();

            SqlDataReader reader = await cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection);
            if (reader.HasRows)
            {
                DataTable dt = new DataTable();
                dt.Load(reader);

                foreach (DataRow dr in dt.Rows)
                {
                    names.Add(dr["Name"].ToString());
                }
            }
        }
    }

    return names;
}
点赞