3

ユーザーが長時間実行される非同期操作を呼び出すボタンを複数回押す可能性がある場合の処理​​方法。

私の考えは、最初に非同期操作が実行されているかどうかを確認し、キャンセルして再度起動することでした。

これまでのところ、CancellationTokenSource を使用してこの種の機能を構築しようとしましたが、期待どおりに機能していません。2 つの非同期操作が実行されている場合があるため、新しい非同期操作を開始しても「古い」非同期操作はまだキャンセルされず、resul 処理が混同されます。

この種のケースを処理する方法の提案や例はありますか?

public async void Draw()
{
    bool result = false;

    if (this.cts == null)
    {
        this.cts = new CancellationTokenSource();

        try
        {
            result = await this.DrawContent(this.TimePeriod, this.cts.Token);
        }
        catch (Exception ex)
        {}
        finally
        {
            this.cts = null;
        }
    }

    else
    {
        this.cts.Cancel();
        this.cts = new CancellationTokenSource();

        try
        {
            result = await this.DrawContent(this.TimePeriod, this.cts.Token);
        }
        catch (Exception ex)
        {}
        finally
        {
            this.cts = null;
        }
    }

}

編集: 最後に、2 つの非同期操作が短時間で実行されていることは悪くないと思います (新しい操作が実行され、古い操作がまだキャンセルされていない場合)。

ここでの本当の問題は、エンドユーザーに進行状況を表示する方法です。古い非同期操作が終了すると、進行状況インジケーターがエンドユーザーから隠されますが、新しく開始された非同期操作はまだ実行されています。

EDIT2: DrawContent(...) 内部では、ThrowIfCancellationRequested を使用しているため、実行中のタスクをキャンセルしても問題ないようです。

進捗表示について。Draw() が呼び出されると、ロード インジケーターが表示されるように設定し、このメソッドが終了すると、ロード インジケーターを非表示にします。そのため、新しい非同期操作を開始した後に前の非同期操作がキャンセルされると、読み込みインジケーターが非表示に設定されます。「古い」メソッドが終了したときに別の非同期メソッドがまだ実行されているかどうかを追跡するにはどうすればよいですか。

4

3 に答える 3

0

BackgroundWorker パターンに従って、DrawContent のループから抜け出してみませんか?

private bool _cancelation_pennding=false;
private delegate DrawContentHandler(TimePeriod period, Token token)
private DrawContentHandler _dc_handler=null;

.ctor(){
    this._dc_handler=new DrawContentHandler(this.DrawContent)
}
public void CancelAsync(){
    this._cancelation_pennding=true;
}
public void Draw(){
    this._dc_handler.BeginInvoke(this.TimePeriod, this.cts.Token)
}
private void DrawContent(TimePeriod period, Token token){
    loop(){
        if(this._cancelation_pennding)
        {
            break;
        }

        //DrawContent code here
    }
    this._cancelation_pennding=false;
}
于 2014-02-07T20:10:04.733 に答える
0

cts.Cancel() を呼び出しても、Task は自動的に停止しません。Task は、キャンセルが要求されているかどうかを積極的にチェックする必要があります。次のようなことができます。

public async Task DoStuffForALongTime(CancellationToken ct)
{
    while (someCondition)
    {
        if (ct.IsCancellationRequested)
        {
            return;
        }

        DoSomeStuff();
    }
}
于 2014-01-28T00:17:25.210 に答える