伊勢的新常識  Index  Search  Changes  RSS  Login

Threadを使うときにあわてない、お手軽な制御方法

スレッドを使った Windows Forms アプリケーションであわてない方法

Windows Forms のフォームを別スレッドから操作すると、たいてい例外が発生します。検索すると理由とかいろいろ書いてるけど、結局どうすればいいということはあまり書かれてないですよね。

回避方法はいろいろありますが、僕が使っている方法は以下のような方法です。

  • スレッドを使っているクラスにイベントを定義
  • 親となるフォームをコンストラクタで渡す
  • スレッドからフォーム上の値を変えたいときは、イベントを親となるフォームへ Invoke する

イベントハンドラは、規約によって (object, EventArgs) なので、イベントのデリゲートと、イベントデータを引数にとる関数を定義しておけば手軽にフォームのスレッドにデータを送ることができます。

で、上記の処理をこういうクラスを書いて定型化しています。

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

namespace EbiSoft.Library
{
    /// <summary>
    /// 別スレッドで動作し、イベントを親フォームに通知するオブジェクトの基本クラスです
    /// </summary>
    public abstract class AsyncObject
    {
        /// <summary>
        /// 親となるフォーム
        /// </summary>
        protected readonly Form Owner;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        /// <param name="owner">親フォーム</param>
        public AsyncObject(Form owner)
        {
            Owner = owner;
        }

        /// <summary>
        /// 親フォームにイベントを通知します
        /// </summary>
        /// <param name="d">呼び出すイベントのデリゲート</param>
        /// <param name="e">送信するイベントデータ</param>
        protected void InvokeEvent(Delegate d, EventArgs e)
        {
            if (d != null)
            {
                // イベントを通知
                if (Owner != null)
                    Owner.Invoke(d, this, e);
            }
        }
    }
}

あとは、このクラスを継承して、このように使います。InvokeEvent 呼ぶだけなのでちょー簡単。

namespace EbiSoft.AnySoft
{
    private class TestAsyncObject : AsyncObject
    {
        public event EventHandler TestEvent;
        
        private Thread thead;
        
        public TestClass(Form owner) : base(owner)
        {
            // 処理を行うスレッドを開始する
            thread = new Thead(new TheadStart(ThreadAction));
            thread.Start();
        }
        
        private void ThreadAction()
        {
            // スレッド内で行う処理
            
            // なにかあったら、イベントを呼び出して親フォームへ通知する
            InvokeEvent(TestEvent, this, EventArgs.Empty);
        }
    }
}

Last modified:2007/10/07 00:20:31
Keyword(s):
References:[SideMenu] [技術ドキュメント]