我有一个从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。
答案 0 :(得分:22)
您在后台线程上排队项目(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);
}
答案 1 :(得分:1)
您可以使用与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
处理程序(订阅者)。
答案 2 :(得分:-2)
在主线程中尝试使用此代码:
SmartQueue smartQueue = new SmartQueue();
public Form1()
{
InitializeComponent();
smartQueue.ItemAdded += new SmartQueue.ItemAddedEventHandler(smartQueue_ItemAdded);
}
void smartQueue_ItemAdded(object sender, EventArgs e)
{
// add your code in here
}