無限ループはボタンクリックイベント等に手続き型で記載すると、フォームが固まってしまう(ように見える)ので、別スレッドにしないと不自然なアプリになる。いろいろ調べてようやくサンプルができたのでメモ。async/awaitとtaskを使うので、新しめの.NETバージョンが必要っぽい。
まずはフォームの作成。ボタン1つとテキストボックス1つ。なんとなくテキストボックスはMultilineプロパティをtrueに設定(複数行対応)。
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
int i = 0;
for (; ; ) //無限ループ
{
await Task.Run(() =>
{
System.Threading.Thread.Sleep(800);
//800ミリ秒待つだけ
});
this.textBox1.Text += i.ToString(); //iの値をテキストボックスへ追記
if (i == 7)
{
break; //7まで書いたらループを抜ける
}
i++;
}
}
}
}
button1_clickイベントには非同期で行う旨の「async」を追記。「await Task.Run」で時間のかかる処理(別スレッドの処理)を記載。
Sleepは厳密には「処理」ではなく、CPUをお休みさせるものらしい(CPUパワーを要しない)が、CPUパワーが必要な時間のかかる処理の場合でも同じように記載すれば良いっぽい。
これでボタンを押すと0から7までの数字を、800ミリ秒ずつ間をあけて、テキストボックスに書くものができた。
続いて「開始ボタン」と「停止ボタン」で制御するタイプの場合。
まずはフォームを作成。今度はボタン2コとテキストボックス1コ(なんとなくMultilineをtrueに設定)。
「開始」が「button1」、停止が「button2」です。コードは以下。
namespace スレッド練習2
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.button2.Enabled = false;
//起動時は停止ボタンを無効化
}
private async void button1_Click(object sender, EventArgs e)
{
// 開始ボタンでスレッド開始
this.button1.Enabled = false; //開始ボタンを無効化
this.button2.Enabled = true; //停止ボタンを有効化
int i = 0;
for (; ; )
{
await Task.Run(() =>
{
System.Threading.Thread.Sleep(800);
});
this.textBox1.Text += "1";
i++;
if (this.button2.Enabled == false)
{
this.button1.Enabled = true;
break;
//停止ボタンが無効化されていたら開始ボタンを
//有効化してループを抜ける
}
}
}
private void button2_Click(object sender, EventArgs e)
{ //停止ボタンのイベント
this.button2.Enabled = false; //停止ボタンを無効化
//処理を重複して開始させたくないので、
//ここにbutton1有効化処理は書かない
}
}
}
起動時は「停止ボタン」が無効化されて起動。今見返してみると、起動時に停止ボタンを無効化する「this.button2.Enabled = false;」は、Form_Loadイベントに書いたほうが良かったか。
「開始ボタン」をクリックすると、無限ループ開始。フォームは固まる事なく、延々"1"が記載され続ける。
「停止ボタン」をクリックすると無限ループを抜ける。
以上。