Taskをつかってディレイ動作を実現する

なにか動作をさせるときに強制的に遅延させるには、簡単にやるなら所望の動作の寸前に Thread.Sleep を入れます。ただ、ご存じのとおり Sleep は、他の動作もプロテクトしてしまうので実際は使い物になりません。

かといって、ちょっとディレイさせたいだけなのにスレッドを起動するというのも大げさです。その場合は Task.Delay を使いましょう。Task の裏側ではスレッドを起動しており、文法でスレッドを巧みに隠しているだけなのですけれど。(笑)

Form に button1, button2, button3, button4 と pictureBox1, pictureBox2, pictureBox3 を配置してください。また、timer1 というタイマーも配置しておいてください。

button1 を押したら1秒後に pictureBox1 が緑→赤になります。

button2 を押したら2秒後に pictureBox2 が緑→赤になります。

button3 を押したら3秒後に pictureBox3 が緑→赤になります。

button4 を押したら pictureBox1, pictureBox2, pictureBox3 がすべて緑に戻ります。

Task.Delay の効き目を実感するには、button3 → button2 → button1 の順に素早く押せばわかりやすいです。button3 でたとえ3秒間のディレイがあっても、button2、button1 を押すことが可能なことが実感できるでしょう。

タスクへの引数として Action 型という動きそのものを渡せるというのが、いまどきの言語機能という感じがしますね。

using System;
using System.Drawing;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace aaa
{
	public partial class Form1 : Form
	{

		int Req1 = 0;
		int Req2 = 0;
		int Req3 = 0;

		public Form1()
		{

			InitializeComponent();

			timer1.Interval = 100;
			timer1.Start();

			// ペイントイベントハンドラを登録する.
			pictureBox1.Paint += pictureBoxN_Paint;
			pictureBox2.Paint += pictureBoxN_Paint;
			pictureBox3.Paint += pictureBoxN_Paint;

		}

		private async void button1_Click( object sender, EventArgs e )
		{
			int msec_delay = 1000;
			Action act = (() => Req1 = 1 );

			await RequestTrigger( msec_delay, act );
		}

		private async void button2_Click( object sender, EventArgs e )
		{
			int msec_delay = 2000;
			Action act = (() => Req2 = 1 );

			await RequestTrigger( msec_delay, act );
		}

		private async void button3_Click( object sender, EventArgs e )
		{
			int msec_delay = 3000;
			Action act = (() => Req3 = 1 );

			await RequestTrigger( msec_delay, act );
		}

		private async Task RequestTrigger( int msec, Action set_flag_action )
		{
			await Task.Delay( msec );
			set_flag_action();
		}

		private void button4_Click( object sender, EventArgs e )
		{
			Req1 = 0;
			Req2 = 0;
			Req3 = 0;
		}

		private void pictureBoxN_Paint( object sender, PaintEventArgs e )
		{

			PictureBox pbx = sender as PictureBox;

			if ( pbx != null )
			{

				int req;

				if ( pbx == pictureBox1 )
				{
					req = Req1;
				}
				else if ( pbx == pictureBox2 )
				{
					req = Req2;
				}
				else
				{
					req = Req3;
				}

				if ( req == 1 )
				{
					using ( SolidBrush sb = new SolidBrush( Color.Red ) )
					{
						e.Graphics.FillRectangle( sb, pbx.ClientRectangle );
					}
				}
				else
				{
					using ( SolidBrush sb = new SolidBrush( Color.Lime ) )
					{
						e.Graphics.FillRectangle( sb, pbx.ClientRectangle );
					}
				}

			}

		}

		private void timer1_Tick( object sender, EventArgs e )
		{
			this.Invalidate( true );
		}
	}
}