none
非同期処理中にフォームが閉じられた時、非同期処理後の処理が走行してほしくない RRS feed

  • 質問

  • Visual C# 2019
    .NET Framework 4.7.2

    下記(部分的に抜粋)のように、async / await によって非同期処理を実施し、その非同期処理が
    完了後の制御があったとします。

            private async void retrieveButton_Click(object sender, EventArgs e)
            {
                connectionOpenButton.Enabled = false;
                retrieveButton.Enabled = false;
                stopButton.Enabled = true;
                connectionCloseButton.Enabled = false;
    
                userInfoList.Clear();
                retrieveCountLabel.Text = "";
                tokenSource = new CancellationTokenSource();
                await Retrieve(tokenSource.Token);
                
                connectionCloseButton.Enabled = true;
                retrieveButton.Enabled = true;
                stopButton.Enabled = false;
                connectionCloseButton.Enabled = true;
            }

    非同期処理 await Retrieve() が走行中に、中断ボタンなどで CancellationTokenSource.Cancel = true とした時は後続処理が走って構わないのですが、フォームが閉じられた時、もはや後続処理は不要なわけなので、処理してほしくありません。
    FormClosed() でも CancellationTokenSource.Cancel = true を実施しますが、非同期処理がキャンセルされるだけで、後続処理は裏で動いてしまっています。
    一般的・常套手段的に、フォームが閉じられた場合に限り、後続処理を走行させない方法はどのようにするものなのでしょうか?

    2020年11月6日 4:52

回答

  • 一般的や常套手段といえる方法は知らないけど、CancelationTokenSource.Cancelの前にキャンセル理由のフラグを立てておくのは?

    private async void retrieveButton_Click(object sender, EventArgs e)
    {
        connectionOpenButton.Enabled = false;
        retrieveButton.Enabled = false;
        stopButton.Enabled = true;
        connectionCloseButton.Enabled = false;
    
        userInfoList.Clear();
        retrieveCountLabel.Text = "";
        tokenSource = new CancellationTokenSource();
    
        try
        {
            await Retrieve(tokenSource.Token);
        }
        catch (TaskCanceledException)
        {
            if (isFormClosed)//後続がすべて不要なら
            {
                return;
            }
        }
        
        if (!isFormClosed)//部分的に不要なら
        {
            connectionCloseButton.Enabled = true;
            retrieveButton.Enabled = true;
            stopButton.Enabled = false;
            connectionCloseButton.Enabled = true;
        }
    }
    
    private bool isFormClosed = false;
    
    protected override void OnClosed(EventArgs e)
    {
        isFormClosed = true;
        tokenSource?.Cancel();
        base.OnClosed(e);
    }

    なお、提示されているコードだとretrieveButton_Clickの戻り値がTaskではないため、TaskCanceledExceptionが発生すると、後続の処理はキャンセル理由を問わず実行されません。


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 編集済み gekkaMVP 2020年11月6日 9:23
    • 回答としてマーク takiru 2020年11月18日 0:22
    2020年11月6日 9:18

すべての返信

  • 一般的や常套手段といえる方法は知らないけど、CancelationTokenSource.Cancelの前にキャンセル理由のフラグを立てておくのは?

    private async void retrieveButton_Click(object sender, EventArgs e)
    {
        connectionOpenButton.Enabled = false;
        retrieveButton.Enabled = false;
        stopButton.Enabled = true;
        connectionCloseButton.Enabled = false;
    
        userInfoList.Clear();
        retrieveCountLabel.Text = "";
        tokenSource = new CancellationTokenSource();
    
        try
        {
            await Retrieve(tokenSource.Token);
        }
        catch (TaskCanceledException)
        {
            if (isFormClosed)//後続がすべて不要なら
            {
                return;
            }
        }
        
        if (!isFormClosed)//部分的に不要なら
        {
            connectionCloseButton.Enabled = true;
            retrieveButton.Enabled = true;
            stopButton.Enabled = false;
            connectionCloseButton.Enabled = true;
        }
    }
    
    private bool isFormClosed = false;
    
    protected override void OnClosed(EventArgs e)
    {
        isFormClosed = true;
        tokenSource?.Cancel();
        base.OnClosed(e);
    }

    なお、提示されているコードだとretrieveButton_Clickの戻り値がTaskではないため、TaskCanceledExceptionが発生すると、後続の処理はキャンセル理由を問わず実行されません。


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    • 編集済み gekkaMVP 2020年11月6日 9:23
    • 回答としてマーク takiru 2020年11月18日 0:22
    2020年11月6日 9:18
  • takiruさん、こんにちは。フォーラムオペレーターのKumoです。 
    MSDNフォーラムにご投稿くださいましてありがとうございます。

    ご質問いただいた件ですが、その後いかがでしょうか。
    gekkaさんから寄せられた投稿はお役に立ちましたか。

    参考になった投稿には [回答としてマーク] をお願い致します。

    設定いただくことで、
    他のユーザーもお役に立つ回答を見つけやすくなります。

    お手数ですが、ご協力の程どうかよろしくお願いいたします。

    MSDN/ TechNet Community Support Kumo ~参考になった投稿には「回答としてマーク」をご設定ください。なかった場合は「回答としてマークされていない」も設定できます。同じ問題で後から参照した方が、情報を見つけやすくなりますので、 ご協力くださいますようお願いいたします。また、MSDNサポートに賛辞や苦情がある場合は、MSDNFSF@microsoft.comまでお気軽にお問い合わせください。~

    2020年11月10日 2:20
    モデレータ
  • ありがとうございます。

    それ用の何かが用意されているわけではなく、フラグをたててごにょごにょっとするしかないんですね。

    2020年11月18日 0:25