質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

3回答

5882閲覧

キャンセルボタンをいつでも押せるようにしたい

退会済みユーザー

退会済みユーザー

総合スコア0

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

1クリップ

投稿2018/09/19 05:56

編集2018/10/05 01:58

前提・実現したいこと

VisualStudio2017でC#を利用したプログラムを作成しています。
フォームに開始ボタンと停止ボタンを作成して停止ボタンを押せばいつでもプログラムを停止出来るようにしたいのですが、躓いています。
流れ
button1_Clickをクリック

First_run();を開始

First_run();内のcom();(ループ文)を開始

com();のループが終わり次第、com2();を開始
上記のどこでも押せて処理を停止できるようにしたいです。
下記の内容ですとcom();のループ途中では停止ボタンは押せない状況です。
現状では、Application.Exit();でフォームごと消してしまっていますが、消さずにすべての処理を止めたい場合はどう記述すればよいでしょうか。
※com();をasnycで非同期処理にしてみましたが、変わらずボタンは押せませんでした。
※First_run()をasnycで非同期処理にしてみるとcom();だけではなく次のcom2();も動いてしまってしまいうまくいきませんでした。

ソースコード

C#

1 //開始ボタン 2 public void button1_Click(object sender, EventArgs e) 3 { 4 First_run(); 5      //上から順番に処理を行いたい 6 } 7public void First_run() 8 { 9 com(); 10        //com();のループが終わってからcom2();を実行する 11 com2(); 12 13 } 14public void com() 15 { 16 //ループ処理(trueになればループ終了) 17**//ここにasnycやawaitを入れる?入れても停止ボタン押せませんでした** 18 } 19public void com2() 20 { 21 //処理 22 } 23public void button2_Click(object sender, EventArgs e) 24 { 25 //アプリケーションを終了させる 26 Application.Exit(); 27 }

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2018/10/04 04:25 編集

あああ
退会済みユーザー

退会済みユーザー

2018/09/26 14:37 編集

コードが用意できたので回答に差し替えます
guest

0

マルチスレッドなどで非同期処理としても、その処理途中でフラグチェックなどで、キャンセルの可否を判断しないとどうしようもありません。
そのcom、com2関数の中の処理ループで、キャンセルかどうかの判断を入れ、キャンセルの場合は処理を中断し、非同期処理を終了させるというコードを組む必要があります

投稿2018/09/19 08:26

y_waiwai

総合スコア87747

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

x_xさんの回答を補足します(コードができたので)。

私もCancellationTokenについて悩んだくちです。わかる範囲で説明をば。。。

まず、登場人物が二人います。CancellationTokenSourceと、それから取得できるCancellationTokenです。このソースを使うことで、トークンにキャンセル指示を出すことができます。ただし、実際になにかしらキャンセルが行われるわけではありません。キャンセル指示が出されたことをトークンを使って確認することができるだけです。"トークンにキャンセル指示が出されたかどうか確認し、指示が出されていればキャンセル処理を行う" という処理を自分で実装する必要がある点に気を付けてください(キャンセルさせたい処理がループであれば、ループの中でトークンを確認し、必要に応じてブレークする)。そうすると、参考のリンクが理解しやすいと思います。

また、キャンセル指示はリセットできません。もう一度処理を実行し、キャンセルしたい場合、ソースを再作成しなければならないことに留意してください。

実際に書いてみると次のようになります。
button1を何度も押せるのはまずいので、状況に応じて有効化無効化します。

c#

1using System; 2using System.Diagnostics; 3using System.Threading; 4using System.Threading.Tasks; 5using System.Windows.Forms; 6 7namespace WindowsFormsApp1 8{ 9 public partial class Form1 : Form 10 { 11 // キャンセレーショントークンソース(Button2で参照します) 12 private CancellationTokenSource CancellationTokenSource; 13 14 public Form1() 15 { 16 InitializeComponent(); 17 18 button1.Enabled = true; 19 button2.Enabled = false; 20 } 21 22 // 開始ボタン 23 public void button1_Click(object sender, EventArgs e) 24 { 25 button1.Enabled = false; 26 button2.Enabled = true; 27 28 // ソースを作成します 29 this.CancellationTokenSource = new CancellationTokenSource(); 30 31 // 処理を開始します(キャンセルトークンを渡す必要があります) 32 First_run(CancellationTokenSource.Token); 33 } 34 // キャンセルボタン 35 public void button2_Click(object sender, EventArgs e) 36 { 37 // キャンセル指示を出します 38 CancellationTokenSource.Cancel(); 39 40 // ソースを破棄します(使い切りのものなので) 41 CancellationTokenSource = null; 42 43 button1.Enabled = true; 44 button2.Enabled = false; 45 } 46 47 public async Task First_run(CancellationToken token) 48 { 49 await com(token); 50 com2(); 51 52 } 53 private async Task com(CancellationToken token) 54 { 55 var count = 0; 56 var loopNum = 300; 57 58 //ループ処理(trueになればループ終了) 59 while (count < loopNum) 60 { 61 // 少し重い処理(0.01sec) 62 await Task.Delay(TimeSpan.FromSeconds(0.01)); 63 Debug.WriteLine("com実行中..."); 64 65 // キャンセル指示が出ているか確認します 66 if (token.IsCancellationRequested) 67 { 68 // キャンセル処理 69 Debug.WriteLine("comをキャンセルします..."); 70 71 // ループ終了 72 break; 73 } 74 75 loopNum++; 76 } 77 78 // キャンセルしてもここは実行されるので注意してください 79 } 80 public void com2() 81 { 82 Debug.WriteLine("com2実行中..."); 83 } 84 } 85}

少し気になったのですが、ループ処理内で行っている処理は非同期処理でしょうか。
そうでなければUIが固まり、ボタンを押すに押せなくなるかもしれません。。
同期処理になっているのであれば、ループ全体を Task.Run(() => { .... }) の中に入れてしまいましょう。

c#

1 await Task.Run(() => 2 { 3 //ループ処理(trueになればループ終了) 4 while (count < loopNum) 5 { 6 // 少し重い処理(0.01sec) 7 //await Task.Delay(TimeSpan.FromSeconds(0.01)); 8 Debug.WriteLine("com実行中..."); 9 10 // キャンセル指示が出ているか確認します 11 if (token.IsCancellationRequested) 12 { 13 // キャンセル処理 14 Debug.WriteLine("comをキャンセルします..."); 15 16 // ループ終了 17 break; 18 } 19 20 //loopNum++; 21 } 22 }, token);

投稿2018/09/26 14:53

編集2018/09/26 15:01
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問