2014-01-08 1 views
4
나는 그래서 난 윈폼을 사용하여 몇 가지 테스트를했다 비동기를 탐구하고 C# 5.0에서 키워드 대기 시작 했어

실행,하지만 지금은 상황이 붙어있는 동안 :자료 UI 스레드 긴 방법을 기다리고 사용하고 비동기

내 요점은 데이터베이스에서 쿼리를 실행하는 것입니다. 쿼리가 완료되지 않은 상태에서 양식에로드하는 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; 
    } 

을 그리고 난 여기에 메서드를 호출 : 내가 때까지 회전하는 형태의 편재 로딩 이미지 GIF를 지금

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); 
    } 

을 메서드가 실행 중일 때 GetItensFromDatabase 메서드가 호출되고, 메서드가 종료되면 gif가 다시 회전합니다.

그래서 GetItensFromDatabase 메서드가 실행되는 동안 gif를 회전 시키려면 어떻게해야합니까?

당신은 당신의 async 방법 내부 await 키워드를 사용할 수도 있지만 awaitable 작업이 없기 때문에, 당신은 TaskFactory 사용하여 메서드 내 명시 적으로 Task을 만들어야합니다
+0

GIF는 어디에 있습니까? – Lloyd

+2

메서드에'async'를 두드려도 자동으로 비동기/비 차단이되지 않습니다 ... –

답변

2

:

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 포인트로 밖으로, 또 다른 (더 나은) 해결책은 SqlDataAdapter 대신 SqlDataReader을 사용하는 것입니다. 그 이유는 SqlDataReader에는 async 개의 메서드를 사용할 수 있습니다. 즉, 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 키워드를 사용할 수 있었습니까? 메서드가 있지만 기다릴 수있는 작업이 없기 때문에 .... " 그래서, 당신이 말하려고하는 것은 내가 긴 루프 (예를 들어) Ui 스레드를 해제하려면 해당 루프 안에 await 키워드를 사용할 수있는 경우? 다음과 같은 것 : Task.Delay (200); – mmarques

+1

@johnnycardy,'Task.Factory.StartNew'를 사용하여 ** 동기 IO 바인딩 작업 **을 풀 스레드로 오프로드하지 않아야합니다. 대신에 ADO.NET에서 제공하는'async' API를 사용하고 결과에'await'을 사용해야합니다. – Noseratio

관련 문제