かなり調べたんだけどスマートなかつ完璧なものは見つからなかったので
作成してみた。
これが、合ってるかわからないけど、思うように動くので参考にしてください。
今回はメインフォームがメインスレッドとします。
OnClassがイベント受け取り
わざと2秒の待機を設置しています。
サブクラスは非同期処理で動きます。
メインスレッドのOnClassに時間を消費してもサブクラスの非同期は待ってくれません。
どんどんイベントを送ってきます。しかし、送られてくる情報は常に変わるため
思った情報が来ない時があります。
これではプログレスバーが飛び飛びのかっちょ悪いものになるでしょう!
そこでイベント発行時の情報を固定して
OnClassに渡す必要があります。
これらもスマートに作るためにカスタム
EventArgを作成します。
非同期スレッドから同期スレッドにイベントを渡す場合
FORMのスレッド情報を非同期スレッドに渡す必要がありました。
渡すのにthisとかを組み込むのがスマートじゃない!
今回は非同期処理のClass側に
SynchronizationContext
を組み込みます。
これは今現在のスレッド情報を変数に入れることができます。
メインスレットの時に実行するとメインスレッドの情報を取得することができるんですね!
---------------------------------------メインスレッド
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 thredtest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
Class1 class1;
private void Form1_Load(object sender, EventArgs e)
{
class1 = new Class1();
class1.CountEvent += OnClass;
class1.Start();
}
//private EventHandler OnClass(object sender ,EventArgs e)
private void OnClass(int CountEvent)
{
label1.Text = CountEvent.ToString() ;
Console.WriteLine(CountEvent + "カウント:スレッドID:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
//System.Threading.Thread.Sleep(2000);
}
}
}
こっちが非同期Classです。
new Class1を作成したときはまだ、メインクラスで動作しているので
testSync = SynchronizationContext.Current;
はメインクラスの情報が入ります。
ただし、thisと違い変数などを見ることはできません。
重たい処理
Eventset()内に置きましょう
ここではスリープ 1秒させます。
重たい処理1秒が完了したらイベントを発生させます。
処理方法としては
testSync.Post(_ => CountEvent(CountSet) , null);
です。
CountSet
はその時の情報を入れてメインスレッドに渡します。
クラスで生成したCountint2 は非同期で+1されていきますので
この情報をそのまま渡しても1,2,3,4,5,6とメインスレッドで受け取れるものでは
ありませんん。
Eventset()内で変数を作成してここに
Countint2 の値を入れます。
int CountSet = 0;
その後
testSync.Post(_ => CountEvent(CountSet) , null);
これでメインスレッドに変数を渡すと
メインスレッドの処理が遅くても(今回は2秒の待ち処理を入れても)
渡された変数は1,2,3.4.5.6.7.8.9.10と順番に変化します。
6を渡された時には非同期スレッドは完了してClass1の
class1 = new Class1();
これ自体は消失していますが、10までちゃんとイベントが発生します。
---------------------------------------サブスレッドClass
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace thredtest
{
class Class1
{
public int Countint2 { get; set; }
private readonly SynchronizationContext testSync;
public delegate void CountEventArg(int e);
public event CountEventArg CountEvent;
protected virtual void OnCountEventt(int c) {
CountEvent?.Invoke(c);
}
public Class1()
{
testSync = SynchronizationContext.Current;
Countint2 = 0;
}
public void Start()
{
Console.WriteLine("Class1:スレッドID:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
Task.Run(() => {
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Class1:FOR1:スレッドID:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
Eventset();
Console.WriteLine("Class1:FOR2:スレッドID:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}
});
Console.WriteLine("Class2:スレッドID:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}
public void Eventset()
{
int CountSet = 0;
Countint2 += 1;
//現在の変数をメインスレッドに送る変数にセットする。
//これでイベント発生時の状態を保持して送ることができる。
CountSet = Countint2;
//サブスレッドで重たい処理
System.Threading.Thread.Sleep(1000);
Console.WriteLine("Class1:Eventset1:スレッドID:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
//メインスレッドにイベントを送る
if(DataLoad != null)
MainThredContrl.Post(_ => DataLoad(NetHttpData),null);
Console.WriteLine("Class1:Eventset2:スレッドID:" + System.Threading.Thread.CurrentThread.ManagedThreadId);
}
}
}
すいません、タブがなくなり見にくいですが勘弁してください。