BackgroundWorker (バックグラウンドワーカー)の処理結果をUIスレッドに返却する - C#

BackgroundWorker (バックグラウンドワーカー)の処理結果をUIスレッドに返却するコードを紹介します。

概要

BackgroundWorker のDoWorkイベントは別スレッドで実行されるため、DoWorkイベントハンドラの中ではUIスレッドのコントロールにアクセスできません。DoWorkの処理が終わった際に処理結果をUIスレッドに返すコードを紹介します。

方法1:DoWorkEventArgs の Resultプロパティを利用する方法

DoWorkイベントハンドラの引数のDoWorkEventArgs のResultプロパティを利用すると、DoWorkでの処理結果を返すことができます。

プログラム1:string型を返す例

UI
下図のUIを作成します。

コード
下記のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace BackgroundWorkerResultDemo
{
  public partial class FormStringReturn : Form
  {
    public FormStringReturn()
    {
      InitializeComponent();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
      string resultValue = "Penguin";
      e.Result = (object)resultValue;
    }

    private void button1_Click(object sender, EventArgs e)
    {
      backgroundWorker1.RunWorkerAsync();
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
      string value = e.Result.ToString();
      textBox1.Text = value;
    }
  }
}
解説
Button1のClickイベントでは、BackgroundWorkerの処理を開始します。
private void button1_Click(object sender, EventArgs e)
{
  backgroundWorker1.RunWorkerAsync();
}

BackgroundWorkerのDoWorkイベントのコードは下記になります。今回の例では計算処理などせずに、引数のDoWorkEventArgs のResultプロパティに、戻り値の文字列"Penguin"を設定します。
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
  string resultValue = "Penguin";
  e.Result = (object)resultValue;
}

DoWorkイベントのDoWorkEventArgs のResultプロパティに設定された値は、RunWorkerCompleted イベントのRunWorkerCompletedEventArgs 引数のResultプロパティに反映されます。
RunWorkerCompletedイベントはUIスレッドで動作するため、RunWorkerCompletedイベント内で、RunWorkerCompletedEventArgs 引数のResultプロパティにアクセスすれば、UIスレッドで、DoWorkイベントの処理結果を受け取れます。

下記のコードにより、RunWorkerCompletedEventArgs.Result にアクセスし、DoWorkのDoWorkEventArgs.Result プロパティに代入した、"Penguin"の文字列を取得できます。取得した文字列をtextBox1に表示します。
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  string value = e.Result.ToString();
  textBox1.Text = value;
}
実行結果
プロジェクトを実行します。下図のウィンドウが表示されます。


[button1]をクリックします。テキストボックスに"Penguin"の文字列が表示されます。DoWorkイベントの処理結果をUIスレッドで受け取れています。

プログラム2:クラス(object型)を返す例

UI
下図のUIを作成します。

コード
下記のコードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace BackgroundWorkerResultDemo
{
  public partial class FormObjectReturn : Form
  {
    public class ResultInfo
    {
      public string Name;
      public int age;
      public int weight;
      public int height;
    }

    public FormObjectReturn()
    {
      InitializeComponent();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
      ResultInfo ri = new ResultInfo();
      ri.Name = "ぺんぎん";
      ri.age = 3;
      ri.weight = 45;
      ri.height =102;

      e.Result = ri;
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
      ResultInfo value = (ResultInfo)e.Result;
      textBox1.Text = value.Name + "\r\n";
      textBox1.Text += "age : "+ value.age.ToString() + "\r\n";
      textBox1.Text += "Height : " + value.height.ToString() + "\r\n";
      textBox1.Text += "Weight : " + value.weight.ToString() + "\r\n";
    }

    private void button1_Click(object sender, EventArgs e)
    {
      backgroundWorker1.RunWorkerAsync();
    }
  }
}
解説
Button1のClickイベントでは、BackgroundWorkerの処理を開始します。
private void button1_Click(object sender, EventArgs e)
{
  backgroundWorker1.RunWorkerAsync();
}

BackgroundWorkerのDoWorkイベントのコードは下記になります。。今回の例では計算処理などせずに、ResultInfoオブジェクトを作成し、オブジェクトの各メンバ変数に値を設定し、引数のDoWorkEventArgs のResultプロパティに、 ResultInfoオブジェクトを設定します。
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
      ResultInfo ri = new ResultInfo();
      ri.Name = "ぺんぎん";
      ri.age = 3;
      ri.weight = 45;
      ri.height =102;

      e.Result = ri;
}

先のプログラムの場合と同様に、DoWorkイベントのResult偽って敷いた値は、RunWorkerCompletedイベントのRunWorkerCompletedEventArgs 引数のResultプロパティに反映されます。
RunWorkerCompletedEventArgs 引数のResultプロパティを元のオブジェクトResultInfoにキャストすることで、DoWorkイベントの処理結果を受け取れます。

下記のコードにより、RunWorkerCompletedEventArgs.Result にアクセスし、DoWorkのDoWorkEventArgs.Result プロパティに代入した、ResultInfoオブジェクトの各値を取得できます。取得した複数の値をtextBox1に表示します。
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
      ResultInfo value = (ResultInfo)e.Result;
      textBox1.Text = value.Name + "\r\n";
      textBox1.Text += "age : "+ value.age.ToString() + "\r\n";
      textBox1.Text += "Height : " + value.height.ToString() + "\r\n";
      textBox1.Text += "Weight : " + value.weight.ToString() + "\r\n";
}
実行結果
プロジェクトを実行します。下図のウィンドウが表示されます。


[button1]をクリックします。テキストボックスにDoWorkイベントで設定された値が表示されます。DoWorkイベントの処理結果をUIスレッドで受け取れています。




方法2:Formコントロールのメンバ変数を利用する方法

処理の結果をFormクラスのメンバ変数に格納して結果をUIスレッドに返すコード例です。シンプルな実装コードになりますが、クラスのメンバ変数に結果を代入するため、複数のBackgroundWorkerが動作している場合はそれぞれのBackgroundWorkerが同じメンバ変数にアクセスしないよう制御する必要があります。

プログラム3:string型を返す例

UI
下図のUIを作成します。

コード
下記コードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace BackgroundWorkerResultDemo
{
  public partial class FormStringReturnMemberValue : Form
  {
    private string ReturnValue;

    public FormStringReturnMemberValue()
    {
      InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {
      backgroundWorker1.RunWorkerAsync();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
      ReturnValue = "しろくま";
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
      textBox1.Text = ReturnValue;
    }
  }
}
解説
フォームのクラスのメンバ変数 ReturnValue にDoWorkイベントから結果を設定します。RunWorkerCompletedイベントでReturnValue 変数を参照することで、DoWorkイベントの結果を取得できます。今回の例では、テキストボックスにDoWorkイベントの結果の文字列を表示します。
実行結果
プロジェクトを実行します。下図のウィンドウが表示されます。


[button1]をクリックします。テキストボックスにBackGroundWorkerのDoWorkイベントからの戻り値 "しろくま" の文字列が表示されます。

プログラム4:クラス(object型)を返す例

UI
下図のUIを作成します。

コード
下記コードを記述します。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace BackgroundWorkerResultDemo
{
  public partial class FormObjectReturnMemberValue : Form
  {
    public class ResultInfo
    {
      public string Name;
      public int age;
      public int weight;
      public int height;
    }

    private ResultInfo ReturnValue;

    public FormObjectReturnMemberValue()
    {
      InitializeComponent();
    }

    private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    {
      ReturnValue = new ResultInfo();

      ReturnValue.Name = "あひる";
      ReturnValue.age = 4;
      ReturnValue.weight = 12;
      ReturnValue.height = 32;
    }

    private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
      textBox1.Text = ReturnValue.Name + "\r\n";
      textBox1.Text += "age : " + ReturnValue.age.ToString() + "\r\n";
      textBox1.Text += "Height : " + ReturnValue.height.ToString() + "\r\n";
      textBox1.Text += "Weight : " + ReturnValue.weight.ToString() + "\r\n";
    }

    private void button1_Click(object sender, EventArgs e)
    {
      backgroundWorker1.RunWorkerAsync();
    }
  }
}
解説
フォームのクラスのメンバ変数 ReturnValueにDoWorkイベント内で戻り値を設定します。ReturnValue変数はResultInfo型のクラスであるため、インスタンスの作成もDoWorkイベント内で実行しています。RunWorkerCompletedイベントでReturnValue 変数を参照することで、DoWorkイベントの結果を取得します。今回の例ではReturnValueオブジェクト内のメンバ変数の値をテキストボックスに表示します。
実行結果
プロジェクトを実行します。下図のウィンドウが表示されます。


[button1]をクリックします。テキストボックスにBackGroundWorkerのDoWorkイベントからの戻り値のオブジェクト(ResultInfo)の値が表示されます。


著者
iPentecのメインプログラマー
C#, ASP.NET の開発がメイン、少し前まではDelphiを愛用
最終更新日: 2017-09-14
作成日: 2017-01-11
iPentec all rights reserverd.