2

タスクを使用してデータベースなどからデータを読み取ります。Dataaccess-API/-Layerを変更できないと仮定します。

このデータアクセスには時間がかかる場合があります(ネットワークトラフィックなど)。ユーザーが選択したアイテムを変更したり、使用可能なデータのサブセットを表示するフィルターを変更したりするたびに読み込まれます。

最後に、Task-Start-Methodの例を少し示します。

私の質問は次のとおりです。タスクの実行中にユーザーがフィルター/選択を変更した場合、どうすればタスクの実行を停止できますか?キャンセルトークンを使用すると、終了します(タスクで「大きな」ループを使用していないため、すべての反復をチェックすることはできません.IsCancelled

私のアイデアは、新しい値を割り当てる前に、タスクの戻りタイプを使用して、戻りタスクを入力してSelectableVolts確認することでした。IsCancelledしかし、非同期タスクに対してこれを行う方法は?

// added code at the bottom of this question

更新:「あなたの質問が何を求めているのか完全にはわかりませんが、これはいくつかの利用可能なオプションの感触をつかむのに役立つはずです」などのコメントを受け取った後。私の問題を少し明確にしようと思います。少なくとも私はそう願っています;)

  1. ユーザーがデータグリッドでオブジェクトを選択します
  2. ViewModelはデータを必要とし、メソッド/クラス/fooにデータを要求します。
  3. タスク(A)が開始されます
  4. Task(A)はまだ機能しています。ユーザーが別のオブジェクト/行を選択します。
  5. 手順1、2、3が繰り返されます。したがって、タスク(A)をキャンセル/停止して、新しいタスク(B)を開始する必要があります。
  6. Task(B)が終了すると、そのデータが表示されます。Task(A)のデータを利用できるようにすることは決してできません。

したがって、問題は次のとおりです。正しい方法でステップ5と6を達成する方法。

完全なコード:

    private CancellationToken cancelTokenOfFilterTask;
    private CancellationTokenSource cancelTokenSourceOfFilterTask;

private void FilterVolts()
{
    if (IsApplicationWorking)
    {
        cancelTokenSourceOfFilterTask.Cancel();
    }

    // Prepare CancelToken
    cancelTokenSourceOfFilterTask = new CancellationTokenSource();
    cancelTokenOfFilterTask = cancelTokenSourceOfFilterTask.Token;

    IsApplicationWorking = true;
    if (SelectableVolts != null && SelectableVolts.Count >= 0)
    {
        VoltThatIsSelected = null;
        SelectableVolts.Clear();
    }

    Task voltLoadTask = null;
    voltLoadTask = Task.Factory.StartNew<List<SelectableVoltModel>>(() => {
       VoltsLoader loader = new VoltsLoader();
       Thread.Sleep(2000);
       var listOfVolts = loader.LoadVoltsOnFilter(_sourceOfCachableData, ChosenFilter);
            return listOfVehicles;
        }, cancelTokenOfFilterTask).ContinueWith(listSwitcher =>
        {
            switch (listSwitcher.Status)
            {
                case TaskStatus.RanToCompletion:
                    SelectableVolts = new ObservableCollection<SelectableVoltsModel>(listSwitcher.Result);
                    IsApplicationWorking = false;
                    break;
                case TaskStatus.Canceled:
                    Console.WriteLine("Cancellation seen"); // Gets never called
                    break;           
                default:
                    break;
            }
        });
    }

どういうわけか、このメソッドを複数回呼び出すと、すべてがTaskStatus.RanTocompletionどのように実行されますか?キャンセルトークンで何か間違ったことをしていますか?

4

3 に答える 3

1

必要なキャンセル サポートをループに含めることができない理由がわかりません。これを行うにはcancelTokenOfFilterTask、「StartNew」デリゲート内で呼び出しているメソッドに を渡すだけです。次に、そのメソッド内で実行できます

token.ThrowIfCancellationRequested();

が正常に完了したかどうかを確認Taskし、関連する結果に対処するには、継続を使用します

cancelTokenSourceOfFilterTask = new CancellationTokenSource();
cancelTokenOfFilterTask = cancelTokenSourceOfFilterTask.Token;

Task task = null;
task = Task.Factory.StartNew(() =>
{
    VoltLoader vl = new VoltLoader();
    var listOfVolts = vl.LoadVoltsOnFilter(_sourceOfCachableData, ChosenFilter);
    SelectableVolts = new ObservableCollection<SelectableVoltsModel>(listOfVolts);
}, cancelTokenOfFilterTask);

task.ContinueWith(ant => 
{
    switch (ant.Status)
    {
        // Handle any exceptions to prevent UnobservedTaskException.             
        case TaskStatus.RanToCompletion:
            if (asyncTask.Result)
            {
                // Do stuff...
            }
            else
            {
                // Do stuff...
            }
            break;
        case TaskStatus.Canceled:
            // If Cancelled you can start the task again reading the new settings.
            break;
        case TaskStatus.Faulted:
            break;
    }
}, CancellationToken.None, 
   TaskContinuationOptions.None, 
   TaskScheduler.FromCurrentSynchronizationContext());

あなたの質問が何を求めているのか完全にはわかりませんが、これはいくつかの利用可能なオプションの感触をつかむのに役立つはずです.

これが役立つことを願っています。

于 2012-09-26T07:59:31.270 に答える
1

回答:解決策を見つけたと思います。キャンセル要求ごとに CancellationTokenSource をリセットする必要があります。

受け入れられた回答に基づいて更新されたコードを次に示します。何か問題があれば、私はどんな情報にも満足しています:)

    private CancellationToken cancelTokenOfFilterTask;
    private CancellationTokenSource cancelTokenSourceOfFilterTask = new CancellationTokenSource();

    private void FilterVolts()
    {
        if (IsApplicationWorking)
        {
            cancelTokenSourceOfFilterTask.Cancel();
        }

        // Prepare CancelToken
        cancelTokenOfFilterTask = cancelTokenSourceOfFilterTask.Token;

        IsApplicationWorking = true;
        if (SelectableVolts != null && SelectableVolts.Count >= 0)
        {
            VoltThatIsSelected = null;
            SelectableVolts.Clear();
        }

        Task voltsLoadTask = null;
        voltsLoadTask = Task.Factory.StartNew<List<SelectableVoltsModel>>(() => {
            VehicleLoader loader = new VehicleLoader();
            Thread.Sleep(2000); // just for testing, so the task runs a "long" time
            var listOfVolts = loader.LoadVoltsOnFilter(_sourceOfCachableData, ChosenFilter);
            return listOfVolts;
        }, cancelTokenOfFilterTask).ContinueWith(listSwitcher =>
        {
            switch (listSwitcher.Status)
            {
                case TaskStatus.RanToCompletion:
                    SelectableVolts = new ObservableCollection<SelectableVoltModel>(listSwitcher.Result);
                    IsApplicationWorking = false;
                    break;
                case TaskStatus.Canceled:
                    cancelTokenSourceOfFilterTask = new CancellationTokenSource(); // reset Source
                    break;
                default:
                    break;
            }
        });
    }
于 2012-09-28T07:00:56.177 に答える
0

1 つの方法は、 which が呼び出されたときに、トークンにキャンセル要求があった場合にCancellationToken.ThrowIfCancellationRequested Methodをスローするを使用することです。OperationCanceledException

このように使用できます

    var cancelTokenSourceOfFilterTask = new CancellationTokenSource();
    var cancelTokenOfFilterTask = cancelTokenSourceOfFilterTask.Token;

    Task.Factory.StartNew(() =>
    {
        VoltLoader vl = new VoltLoader();

        //if a request is raised for cancellation then an exception will be thrown
        cancelTokenOfFilterTask.ThrowIfCancellationRequested();

        var listOfVolts = vl.LoadVoltsOnFilter(_sourceOfCachableData, ChosenFilter);

        SelectableVolts = new ObservableCollection<SelectableVoltsModel>(listOfVolts);
    }, cancelTokenOfFilterTask);

上記のコードは、次のコード スニペットと同じです

    var cancelTokenSourceOfFilterTask = new CancellationTokenSource();
    var cancelTokenOfFilterTask = cancelTokenSourceOfFilterTask.Token;

    Task.Factory.StartNew(() =>
    {
        VoltLoader vl = new VoltLoader();

        //if a request is raised for cancellation then an exception will be thrown
        if (cancelTokenOfFilterTask.IsCancellationRequested) 
           throw new OperationCanceledException(cancelTokenOfFilterTask);

        var listOfVolts = vl.LoadVoltsOnFilter(_sourceOfCachableData, ChosenFilter);

        SelectableVolts = new ObservableCollection<SelectableVoltsModel>(listOfVolts);
    }, cancelTokenOfFilterTask);

上記は使用方法の例にすぎません。詳細については、タスク コンストラクターでキャンセル トークンが必要な理由について、この SO の質問を読むことができます。

于 2012-09-26T07:42:09.110 に答える