読者です 読者をやめる 読者になる 読者になる

Natural Software

KinectなどのDepthセンサーを中心に活動しています

C# でカンタンスレッド処理

C# 備忘録
  1. アプリ作ってて処理が重くて UI が固まるのでスレッドにしようと思って、
  2. 自分でスレッドクラス作ってたら、
  3. そう言えばコンポーネントにそんなのがあったなぁというのを思い出して調べたら、
  4. 簡単な BackgroundWorker というのがあったんだね(笑)


簡単な自作スレッドクラス作った後に BackgroundWorker を見つけ、お試しした後に @IT でサンプルがあった。


まぁ、それでもせっかくやったので備忘録がてらサンプルコードを残しとく。
それにしても簡単だ。。。
DoWork だけがスレッド違いなので、ここからコンポーネントを扱ってはいけない、ということさえ覚えておけばいいみたい。
途中の処理は ProgressChanged で、終了後の処理は RunWorkerCompleted でそれぞれやれば OK。

using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;

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

        /// <summary>
        /// 表示直前に呼ばれる
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Shown( object sender, EventArgs e )
        {
            EnableComponent( true );
        }

        /// <summary>
        /// コンポーネントの有効/無効を切り替える
        /// </summary>
        /// <param name="enable"></param>
        void EnableComponent( bool enable )
        {
            Trace.WriteLine( Thread.CurrentThread.ManagedThreadId );
#if false
            // フォームは以下のコンポーネントを列挙する
            foreach ( Control control in Controls ) {
                control.Enabled = enable;
            }
#else
            buttonStart.Enabled = enable;
            buttonCancel.Enabled = !enable;
#endif
        }

        /// <summary>
        /// スレッド関数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker1_DoWork( object sender, DoWorkEventArgs e )
        {
            Trace.WriteLine( Thread.CurrentThread.ManagedThreadId );

            BackgroundWorker worker = sender as BackgroundWorker;
            for ( int i = 10; i <= 100; i += 10 ) {
                // キャンセル
                if ( worker.CancellationPending ) {
                    e.Cancel = true;
                    break;
                }

                // 経過通知
                worker.ReportProgress( i );
                Thread.Sleep( 500 );
            }
        }

        /// <summary>
        /// 経過通知を受け取る
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker1_ProgressChanged( object sender, ProgressChangedEventArgs e )
        {
            Trace.WriteLine( Thread.CurrentThread.ManagedThreadId + ":" + e.ProgressPercentage );
        }

        /// <summary>
        /// スレッド終了後に呼ばれる
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void backgroundWorker1_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e )
        {

            MessageBox.Show( e.Cancelled.ToString() );
            EnableComponent( true );
        }

        private void buttonStart_Click( object sender, EventArgs e )
        {
#if true
            Trace.WriteLine( Thread.CurrentThread.ManagedThreadId );
            EnableComponent( false );
            backgroundWorker1.RunWorkerAsync();
#else
            EnableComponent( false );
            Thread.Sleep( 3000 );
            MessageBox.Show( textBoxName.Text );
            EnableComponent( true );
#endif
        }

        private void buttonCancel_Click( object sender, EventArgs e )
        {
            backgroundWorker1.CancelAsync();
        }
    }
}