Reputation: 655
I'm starting to explore async and wait keywords from c# 5.0 so i made a few test using winforms, but now i'm stuck in a situation:
My point is to run a query from a database and while the query is not completed i want to show a loading gif on form.
This is the method that queries the database:
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;
}
And i call that method here:
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);
}
For now i have a omnipresent loading image gif on the form that is rotating until the method GetItensFromDatabase be called, when the method is running the gif is stop and when the method finishes the gif start rotating again.
So, theres some way to keep the gif rotating while the GetItensFromDatabase method is running ?
Upvotes: 4
Views: 834
Reputation: 3046
You could have used the await
keyword inside your async
method, but since there is no awaitable operation, you should create a Task
explicitly inside your method using the TaskFactory
:
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;
});
}
Edit: As @mmarques points out, another (better) solution is to use SqlDataReader
instead of SqlDataAdapter
. The reason is that SqlDataReader
has async
methods available - meaning you don't need to use TaskFactory
to block a new thread from the thread pool, and you can use async
and 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;
}
Upvotes: 2