我开始探索异步并从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;
}