2014-01-08 23 views
4

我開始探索異步和C#5.0等關鍵字,所以我做了使用的WinForms一些測試運行,但現在我的情況很卡:發佈UI線程同時長的方法是使用的await和異步

我的觀點是從數據庫運行查詢,而查詢未完成時,我想在窗體上顯示加載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旋轉的一些方法?

+0

GIF在哪裏? – Lloyd

+2

只是把'async'打到一個方法不會使它自動地異步/非阻塞... –

回答

2

你可能已經使用了await關鍵字的async方法裏面,但因爲沒有awaitable操作,則應該使用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。原因是SqlDataReaderasync方法可用 - 這意味着您不需要使用TaskFactory來阻塞線程池中的新線程,並且可以使用asyncawait

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; 
} 
+0

它的工作原理,謝謝:) – mmarques

+0

你能解釋一下你的意思嗎?「你可以在你的異步中使用await關鍵字方法,但由於沒有等待操作....「 所以,你想說的是,如果我有一些長循環(例如)我可以使用該循環內的await關鍵字釋放Ui線程?像這樣:await Task.Delay(200); – mmarques

+1

@johnnycardy,你不應該使用'Task.Factory.StartNew'將**同步IO綁定操作**卸載到一個池線程中。您應該使用由ADO.NET提供的'async' API並在其結果中使用'await'。 – Noseratio

相關問題