5

ここには明らかな何かが欠けていると思いますが、タスクを使用して値を取得するときに GUI を更新するにはどうすればよいですか? (BackgroundWorker の代わりに await/async を使用しようとしています)

私のコントロールでは、ユーザーは時間がかかることをするボタンをクリックしました。進行状況を表示できるように、親フォームに警告したい:

private void ButtonClicked()
        {
            var task = Task<bool>.Factory.StartNew(() =>
            {
                WorkStarted(this, new EventArgs());
                Thread.Sleep(5000);
                WorkComplete(this, null);
                return true;
            });

            if (task.Result) MessageBox.Show("Success!");//this line causes app to block
        }

私の親フォームでは、ステータス バーを更新するために WorkStarted と WorkComplete をリッスンしています。

myControl.WorkStarting += (o, args) =>
                {
                    Invoke((MethodInvoker) delegate
                        {
                            toolStripProgressBar1.Visible = true;
                            toolStripStatusLabel1.Text = "Busy";
                        });

                };

私が間違っている場合は修正してください。ただし、「Invoke」が GUI スレッドが使用可能になるのを待っているため、アプリがハングしていますが、「ButtonClicked()」呼び出しが完了するまで使用できません。そのため、デッドロックが発生しています。これにアプローチする正しい方法は何ですか?

4

2 に答える 2

2

タスクが完了するまで、UI スレッドTask.Resultブロックをブロックしています。

これを試して。

private async void ButtonClicked()
{
     var task = Task<bool>.Factory.StartNew(() =>
     {
            WorkStarted(this, new EventArgs());
            Thread.Sleep(5000);
            WorkComplete(this, null);
            return true;
     });

     await task;//Wait Asynchronously
     if (task.Result) MessageBox.Show("Success!");//this line causes app to block
}
于 2013-10-02T14:36:40.227 に答える
1

Task.Runバックグラウンド スレッドでコードを実行するために使用できます。タスクベースの非同期パターンは、次のような進行状況更新のパターンを指定します。

private async void ButtonClicked()
{
  var progress = new Progress<int>(update =>
  {
    // Apply "update" to the UI
  });
  var result = await Task.Run(() => DoWork(progress));
  if (result) MessageBox.Show("Success!");
}

private static bool DoWork(IProgress<int> progress)
{
  for (int i = 0; i != 5; ++i)
  {
    if (progress != null)
      progress.Report(i);
    Thread.Sleep(1000);
  }
  return true;
}

.NET 4.0 をターゲットにしている場合は、Microsoft.Bcl.Async;を使用できます。その場合、TaskEx.Run代わりにを使用する必要がありTask.Runます。を使用してはいけない理由Task.Factory.StartNewについては、ブログで説明しています。

于 2013-10-02T14:51:11.287 に答える