2016-03-24 23 views
0

私は、非同期関数が完了するのを待っているので、UIスレッドでListViewにデータを取り込めます。再移植は、()、まだ完了していないので、C#Asyncファンクションが途中で返される

は、ここでは、コード

public Form1() 
    { 
     InitializeComponent(); 

     Task t = new Task(Repopulate); 
     t.Start(); 
     // some other work here 
     t.Wait(); //completes prematurely 

    } 

    async void Repopulate() 
    {   
     var query = ParseObject.GetQuery("Offer"); 
     IEnumerable<ParseObject> results = await query.FindAsync(); 

     if (TitleList == null) 
      TitleList = new List<string>(); 
     foreach (ParseObject po in results) 
      TitleList.Add(po.Get<string>("title")); 
    } 

TitleList = nullをForm1の中に()です。したがって、Wait()を使用しました。ただし、関数が完了する前に待機します。

私はここで間違っていますか?

答えて

7

Repopulateメソッドの戻り値の型を変更して、非同期操作を表すタスクを返す必要があります。

また、Task.Waitを呼び出すと、UIスレッドがブロックされ(アプリケーションが応答しなくなる)、フォームコンストラクタから非同期操作を実行しないでください。むしろ、そのForm.Loadメソッドにサブスクライブし、awaitキーワードを使用して非同期操作を実行し、イベントハンドラを非同期に保ちます。非同期操作が完了するまでユーザーがフォームと対話しないようにするには、コンストラクタ内のフォームを無効にして、Loadハンドラの最後でフォームを再度有効にします。

更新:将来の読者の利益のために、私は答えに私のコメントを作り直しています:

Task.Waitは、タスクが完了するまでブロックするために呼び出し元のスレッドが発生します。フォームコンストラクタとイベントハンドラはその性質上、UIスレッド上で実行されるため、Waitを呼び出すとUIスレッドがブロックされます。一方、awaitキーワードは、現在のメソッドが呼び出し元に制御を戻すようにします。イベントハンドラの場合は、UIスレッドがイベント処理を続行できるようになります。待機中のメソッド(イベントハンドラ)は、タスクが完了した後にUIスレッドで実行を再開します。

Task.Waitは、コンストラクタまたはイベントハンドラから呼び出されたかどうかに関係なく、常に呼び出しスレッドをブロックするため、特にUIスレッドで実行しているときは、呼び出しスレッドを使用しないでください。 C#5は、この目的のためにasyncawaitのキーワードを導入しました。ただし、メソッドでのみサポートされ、コンストラクタではサポートされません。この制限は、初期化コードをフォームコンストラクタから非同期イベントハンドラに移動する必要がある主な理由に基づいています。

Task.Wait()が早期に返される理由:元のコードでは、tというタスクは、フォームコンストラクタでインスタンス化したTaskの実行を表します。このタスクはRepopulateで実行されます。ただし、最初のawaitステートメントが発生すると直ちにそのメソッドが戻り、残りのロジックはfire-and-forgetの方法で実行されます。これはasync voidを使用する危険性があります。非同期メソッドがいつ実行を完了したかはわかりません。このため、async voidはイベントハンドラでのみ使用してください。つまり、が最初のawaitになるとすぐにt.Wait()が返されます。

async TaskRepopulateの署名を変更することにより、あなたは今 query.FindAsync()非同期呼び出しと、それを成功する処理を含むその非同期実行が完了したことを表して別のタスク、 を得ています。Task.Runが引数として非同期操作(Func<Task>)を渡されると、返されたタスクは内部のタスクを待つ(unwrap)。このため、Task.StartまたはTask.Factory.StartNewの代わりにTask.Runを使用する必要があります。

+0

これはまだブロック 'Task.Wait()'コールを使用しています – kai

+0

@kai:それについての謝罪;今修正されました。 – Douglas

+0

これは完璧に動作します、ありがとう。 なぜあなたに教えてもらえますか 1)Task.Wait()はUIスレッドを応答不能にしますか? (待つのとは対照的に) 2)Task.Wait()は途中で戻りましたか? (元のコードで) – Crimson7

関連する問題