C# Windows フォームアプリケーションで別スレッドからUIを操作する方法

この記事は、Windows フォームアプリケーション (.NET Framework)の話です。 Windows WPFアプリ (.NET Framework) の場合

HeavyTask_Error だと

System.InvalidOperationException: '有効ではないスレッド間の操作: コントロールが作成されたスレッド以外のスレッドからコントロール 'Othersbutton' がアクセスされました。'

というエラーが出る。

正しくUIを操作するには、HeavyTask_Fixed のように修正する。delegate に対して Invoke で呼び出せばよい。

//エラーが出る
Othersbutton.Enabled = false; 

//修正後 {内は複数行でも可}
Invoke(new Action(() => { Othersbutton.Enabled = false; })); 

コード全体は以下の通り

using System;
using System.Threading.Tasks;
using System.Windows.Forms;
<200b>
namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        bool stop = false;
        public Form1()
        {
            InitializeComponent();
        }
        void HeavyTask_Error()
        {
            Othersbutton.Enabled = false;
            for (int i = 0; i < 30; i++)
            {
                System.Threading.Thread.Sleep(100);
                if (stop) break;
                label1.Text = i.ToString();
            }
            if (stop)
            {
                label1.Text = "Stop!";
            }
            else
            {
                label1.Text = "Completed!";
            }
            Othersbutton.Enabled = true;
        }
        void HeavyTask_Fixed()
        {
            Invoke(new Action(() => { Othersbutton.Enabled = false; }));
            for (int i = 0; i < 30; i++)
            {
                System.Threading.Thread.Sleep(100);
                if (stop) break;
                Invoke(new Action(() => { label1.Text = i.ToString(); }));
            }
            if (stop)
            {
                Invoke(new Action(() => { label1.Text = "Stop!"; }));
            }
            else
            {
                Invoke(new Action(() => { label1.Text = "Completed!"; }));
            }
            Invoke(new Action(() => { Othersbutton.Enabled = true; }));
        }
        private void StartError_Click(object sender, EventArgs e)
        {
            stop = false;
            Task.Run(() => HeavyTask_Error());
        }
        private void StartFixed_Click(object sender, EventArgs e)
        {
            stop = false;
            Task.Run(() => HeavyTask_Fixed());
        }
        private void Stop_Click(object sender, EventArgs e)
        {
            stop = true;
        }
    }
}

f:id:onsanai:20210924105130p:plain

検索用 thread forms