サブスレッドからフォームのコントロール(メインスレッドのコントロール)にアクセスする - C#

サブスレッドからメインスレッドを呼び出すコードを紹介します。

概要

スレッドの終了を待つ方法スレッドの処理完了を待つ方法を用いてスレッドの処理の終了を知ることができますが、この方法ではメインスレッドがブロックされます。
スレッド側から通知してもらえればメインスレッドをブロックせずに済むため、スレッドの処理が終了した際にスレッド側からフォームのコントロールにメッセージを表示させたいことがあります。しかし、スレッド側からメインスレッドのコントロールにアクセスするとアクセスエラーが発生するため、スレッド側からメインスレッドのコントロールにアクセスする場合には同期をとる必要があります。 C#ではInvoke()メソッドを使うことでサブスレッド側からメインスレッドのコントロールにアクセスできます。

プログラム例

コード

Form1.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace ThreadCheck
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    private void button3_Click(object sender, EventArgs e)
    {
      MyThread3 m3 = new MyThread3(this);                      //スレッドクラスの作成
      m3.myEvent += new MyThread3.MyEventHandler(FormUpdate);

      Thread t = new Thread(new ThreadStart(m3.exec));   
      
      t.Start();                                               //スレッド実行

    }

    public void FormUpdate(int a, int b, int c)
    {
      textBox1.Text += string.Format("Complete, {0:d} {1:d} {2:d}\r\n",a,b,c);
    }

  }
}
MyThread3.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ThreadCheck
{
  class MyThread3
  {
    public delegate void MyEventHandler(int a, int b, int c);
    public event MyEventHandler myEvent = null;

    System.Windows.Forms.Control cnt;

    public MyThread3(System.Windows.Forms.Control mainThreadForm)
    {
      cnt = mainThreadForm;
    }

    public void exec()
    {
      System.Threading.Thread.Sleep(3000);
      
      cnt.Invoke(myEvent,new object[3]{1,4,3});
    }
  }
}

解説

MyThread3 m3 = new MyThread3(this);
にてスレッドクラスのインスタンスを生成します。インスタンス生成時にコンストラクタの引数としてメインフォームのインスタンスを与えます。スレッドクラス側でフォームのインスタンスを保持しておきます。
m3.myEvent += new MyThread3.MyEventHandler(FormUpdate);
サブスレッドが完了した際に呼び出されるイベントを設定します。サブスレッド側からメインスレッドのメソッドを直接呼び出さずにデリゲートとして呼び出します。
t.Start();
でスレッドを開始します。
スレッド側で処理が終了すると、
cnt.Invoke(myEvent,new object[3]{1,4,3});
Invokeメソッドを使用しイベント(デリゲート)を呼び出します。イベントは
public delegate void MyEventHandler(int a, int b, int c);
と定義されており、intの引数を3つ取ります。Invoke呼び出しの場合は引数はInvokeの第二引数に与えます。

cnt.Invoke(myEvent,new object[3]{1,4,3});

myEvent(1,4,3);
をInvokeで呼び出していることになります。

著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
掲載日: 2010-05-28
iPentec all rights reserverd.