0

新しいタスクを実行し、いくつかのものを作成し、オブジェクトのリストを返すアプリケーションを開発しています...

新しいタスクを生成するとき、UI スレッドで for ループで変化するプログレスバーをシミュレートする必要があります...そしてタスクの完了後、ビューを更新する必要があります (使用している ViewModel プロパティの値を更新してMVVM パターン)。

問題は、タスクが起動されると GUI がフリーズし、プログレス バーが更新されないことです。タスクは別のスレッドでバックグラウンドで実行されると思いました(プールされているため)。では、なぜ私のGUIがブロックされているのですか??

ここに私のコードのスニペットがあります:

Task<List<Items>> myTask = Task.Factory.StartNew(() => queryHandler.GetItemssStatistics(items, sec, buyer, seller, From, To));

//Here is the simulation of ProgressBar changing that i need to be done when task is started
                    for (int i = 0; i < 100; i++)
                    {
Thread.Sleep(100);
                        StatusValue = i+1;
                    }
//Here is the section i need to do once the task finishes its execution to update my VM
//Wait for the task to finish its execution and retreive results:
                    List<Items> _tempResults = myTask.Result;
                    foreach (Items d in _tempResults)
                    {
                        ResultsList.Add(d);
                    }

                    if (ResultsList.Count == 0)
                    {
                        MessageBox.Show("Sorry, No items matched the defined research criteria!", "Warning",
                                        MessageBoxButton.OK,
                                        MessageBoxImage.Warning, MessageBoxResult.OK, MessageBoxOptions.ServiceNotification);
                    }
                    else
                    {
                        //Show items:
                        ResultsAvailable = Visibility.Visible;

                    }
4

2 に答える 2

2

コードにはいくつかの問題があります。

  • Thread.SleepUIスレッドで使用しています
  • Task<T>.Resultタスクが完了するまでブロックする UI スレッドで再度呼び出しています。

いくつかのことができます:

  • ProgressBar.IsIndeterminate = true進行状況の更新を偽造する代わりに、マーキー スタイルの進行状況バーを表示するために使用する、 を使用しDispatcherTimerて進行状況バーを更新します。
  • タスクの継続を使用して、タスクの完了後に発生する必要があるコードを実行します。または、.NET 4.5 を使用している場合は、言語の新しいasync/await機能を使用できます。

async/await を使用するには:

async Task GetItems()
{
    List<Items> tempResults = await Task.Run(() => queryHandler.GetItemssStatistics(...));
    // the following will be executed on the UI thread automatically
    // after the task is done, keeping the UI responsive
    foreach (Items d in _tempResults)
    {
        ResultsList.Add(d);
    }
}

継続を使用するには:

Task.Factory.StartNew(() => queryHandler.GetItemssStatistics(...))
    .ContinueWith(task => ProcessResults(task.Result), TaskScheduler.FromCurrentSynchronizationContext());

このメソッドは、UI スレッドへのコール バックをマーシャリングするためにFromCurrentSynchronizationContext使用するタスク スケジューラを作成します。SynchronizationContext

明らかに await/async を使用する方がはるかに簡単で、利用できる場合は好みのはずです。

于 2013-03-11T11:56:09.790 に答える
0

UI を呼び出しているため、まだ UI の動作を停止してThread.Sleepいます。プログレスバーを更新したい場合は、別のスレッドを実行するか、プログレスバーの増加をタスクに統合してみてください。
あなたのコードを見ると、タスクの進行状況バーの更新を行う方が良いでしょう!
ユーザーを 10000 ミリ秒待機させています。タスクが前に終了した場合、ユーザーは待機する必要があります
...

//process item
if(progressBar.Dispatcher.CheckAccess()){
progressBar.Value += 1; //maybe calculate the number of items you are processing
}
else {
//send a delegate to the dispatcher
MyDelegate myDel = new MyDelegate(delegate() {
   progressBar.Value += 1;
});    
progressBar.Dispatcher.Invoke(myDel);
}

デリゲートの署名は次のようになります。

public void MyDelegate();

于 2013-03-11T11:34:19.210 に答える