プロジェクトの作成
dotnet new winforms -n プロジェクト名 cd プロジェクト名 code .
ソースコード
using System.Diagnostics;
namespace AsyncSample2;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var panel1 = new FlowLayoutPanel
{
Dock = DockStyle.Fill,
Padding = new Padding(10),
};
var button1 = new Button
{
Size = new Size(100, 50),
Enabled = true,
Text = "実行",
};
var button2 = new Button
{
Size = new Size(100, 50),
Enabled = false,
Text = "キャンセル",
};
var progress1 = new ProgressBar
{
Size = new Size(200, 40),
};
var label1 = new Label()
{
Size = new Size(200,40),
Text = $"{Thread.CurrentThread.ManagedThreadId}: ",
};
panel1.Controls.AddRange(new Control[]
{
button1,
button2,
progress1,
label1,
});
panel1.SetFlowBreak(button2, true);
panel1.SetFlowBreak(progress1, true);
Controls.Add(panel1);
IProgress<int> progress = new Progress<int>(x =>
{
label1.Text = $"{Thread.CurrentThread.ManagedThreadId}: Progress";
progress1.Value = x;
});
CancellationTokenSource? cts = null;
button1.Click += async (s, e) =>
{
label1.Text = $"{Thread.CurrentThread.ManagedThreadId}: Click Start";
button1.Enabled = false;
button2.Enabled = true;
progress1.Value = 0;
cts = new CancellationTokenSource();
try
{
await Task.Run(()=>
{
cts.Token.ThrowIfCancellationRequested();
for(int i = 0; i < 100; i++)
{
//label1.Text = $"{Thread.CurrentThread.ManagedThreadId}: Task.Run{i}";
progress.Report(i+1);
if (cts.IsCancellationRequested)
throw new OperationCanceledException("キャンセル");
Task.Delay(10).Wait();
}
}, cts.Token);
label1.Text = $"{Thread.CurrentThread.ManagedThreadId}: 完了";
}
catch (OperationCanceledException ex)
{
label1.Text = $"{Thread.CurrentThread.ManagedThreadId}: Catch {ex.Message}";
}
finally
{
progress1.Value = 0;
cts.Dispose();
cts = null;
button1.Enabled = true;
button2.Enabled = false;
}
Debug.Print($"{Thread.CurrentThread.ManagedThreadId}: Click End");
};
button2.Click += (s, e) =>
{
cts?.Cancel();
};
}
}//class
実行
dotnet run
実行ボタンを押します。
プログレスバーが一杯なると「完了」のメッセージが表示されます。
実行中に「キャンセル」ボタンを押すとTaskがキャンセルされます。
感想
自分の環境だけかもしれませんがvscodeでデバッグ実行すると、throwで例外がcatchできなかったとエラーが表示されます。
その後F5キーを押して続行すると例外がcatchしたメッセージボックスが表示されます。また、dotnet runで実行した場合は発生しないので、こういうものだと思うことにしています。
ソースコード2
using System.Diagnostics;
namespace AsyncSample2;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var panel1 = new FlowLayoutPanel {
Dock = DockStyle.Fill,
Padding = new Padding(10),
};
var button1 = new Button {
Size = new Size(100, 50),
Enabled = true,
Text = "実行",
};
var button2 = new Button {
Size = new Size(100, 50),
Enabled = true,
Text = "キャンセル",
};
var progress1 = new ProgressBar {
Size = new Size(200, 40),
};
panel1.Controls.AddRange(new Control[]{
button1, button2, progress1,
});
panel1.SetFlowBreak(button2, true);
Controls.Add(panel1);
IProgress<int> progress = new Progress<int>(x =>
{
progress1.Value = x;
});
CancellationTokenSource? cts = null;
button1.Click += async (s, e) => {
if (null != cts)
{
cts.Cancel();
while(null != cts)
{
await Task.Delay(10);
}
}
cts = new CancellationTokenSource();
var _task = Task.Run(()=>{
for(int i = 0; i < 100; i++) {
cts.Token.ThrowIfCancellationRequested();
Task.Delay(10).Wait();
progress.Report(i+1);
}
}, cts.Token);;
try {
progress1.Value = 0;
await _task;
}
catch (OperationCanceledException ex) {
MessageBox.Show($"{ex.Message}", $"例外補足");
}
finally {
this.Text = "";
if (_task.IsCanceled)
{
this.Text = this.Text + "キャンセル";
}
if (_task.IsCompletedSuccessfully)
{
this.Text = this.Text + "成功完了";
}
cts?.Dispose();
cts = null;
}
};
button2.Click += (s, e) =>
{
cts?.Cancel();
};
}
}
コメント