Queueクラスから継承されたカスタムQueueクラスがあります。イベントItemAddedがあります。このイベントのイベントハンドラーで、メソッドを実行しています。しかし、メインスレッドで実行したいのですが、メインスレッド以外で実行されています。やり方がわかりません。なにか提案を ?
//My custom class
using System;
using System.Collections; //Required to inherit non-generic Queue class.
namespace QueueWithEvent
{
public class SmartQueue:Queue
{
public delegate void ItemAddedEventHandler(object sender, EventArgs e);
public event ItemAddedEventHandler ItemAdded;
protected virtual void OnItemAdded(EventArgs e)
{
if (ItemAdded != null)
{
ItemAdded(this, e);
}
}
public override void Enqueue(object Item)
{
base.Enqueue(Item);
OnItemAdded(EventArgs.Empty);
}
}
}
//Winform application
using System;
using System.ComponentModel;
using System.Windows.Forms;
using QueueWithEvent;
namespace TestApp
{
public partial class Form1 : Form
{
SmartQueue qTest = new SmartQueue();
public Form1()
{
InitializeComponent();
qTest.ItemAdded += new SmartQueue.ItemAddedEventHandler(this.QChanged);
}
private void btnStartBgw_Click(object sender, EventArgs e)
{
DisplayThreadName();
bgwTest.RunWorkerAsync();
}
private void bgwTest_DoWork(object sender, DoWorkEventArgs e)
{
try
{
for (int i = 0; i < 11; i++)
{
string valueTExt = i.ToString();
qTest.Enqueue(valueTExt);
System.Threading.Thread.Sleep(5000);
}
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message);
}
}
private void DisplayThreadName()
{
string tName = System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();
txtThreadName.Text = tName;
}
private void QChanged(object sender, EventArgs e)
{
//#########I want this method to run on main thread #############
DisplayThreadName();
}
}
}
前もって感謝します。 SKPaul。
バックグラウンドスレッドでアイテムをキューに入れているため(DoWorkイベントハンドラーはバックグラウンドスレッドで実行されます)、イベントはバックグラウンドスレッドでも発生します。
InvokeRequired
メソッドを使用して、UIスレッドを使用しているかどうかを確認します。そうでない場合は、Invoke
を使用してUIスレッドでコードを実行します。
private void QChanged(object sender, EventArgs e)
{
if (InvokeRequired)
{
Invoke((MethodInvoker)delegate { QChanged(sender, e); });
return;
}
// this code will run on main (UI) thread
DisplayThreadName();
}
別のオプション-ProgressChanged
イベントを使用してアイテムをキューに入れます(WorkerReportsProgress
をtrueに設定することを忘れないでください)。このイベントハンドラーはUIスレッドで実行されます。
private void bgwTest_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = (BackgroundWorker)sender;
for (int i = 0; i < 11; i++)
{
// use user state for passing data
// which is not reflecting progress percentage
worker.ReportProgress(0, i);
System.Threading.Thread.Sleep(5000);
}
}
private void bgwTest_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
string valueTExt = e.UserState.ToString();
qTest.Enqueue(valueTExt);
}
BackgroundWorker
と同じアプローチを使用できます。つまり、AsyncOperation
を次のように組み込んでいます。クラス内のメンバー。作成されたスレッドに操作をディスパッチできます。
protected AsyncOperation AsyncOp;
「null」引数を使用してコンストラクターでインスタンス化します。これにより、現在のスレッドに「バインド」された非同期操作が作成されます。
public SmartQueue()
{
AsyncOp = AsyncOperationManager.CreateOperation(null);
}
次に、AsyncOpを使用してイベントをPost
できます。
public override void Enqueue(object Item)
{
base.Enqueue(Item);
AsyncOp.Post(OnItemAdded, EventArgs.Empty);
}
これにより、SmartQueueインスタンスを作成したのと同じスレッドでOnItemAdded
ハンドラー(サブスクライバー)が実行されます。