2012-12-04 104 views
10

我有一个从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。

+1

Windows窗体或WPF? – Tigran

回答

19

您正在后台线程(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)。

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

谢谢lazyberezovsky,现在它的工作。非常感谢。 –

+7

如果你的主线程没有窗体怎么办?例如一个托盘应用程序的ApplicationContext类。然后调用不可用。 – xr280xr

1

您可以使用同样的方法为BackgroundWorker,即结合AsyncOperation在你的类中的成员,它可以调度操作,它在被创建的线程:此事件处理程序对UI线程上运行。

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处理程序(用户)。

+0

OP不使用WPF - 查看代码示例。 –

-1

尝试使用这个代码在主线程:

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 
} 
+0

这是简单的事件订阅,已由OP完成。它如何解决多线程问题? –

+0

对于多线程问题,您需要在测试并调用它之前将委托分配给临时变量,以便线程安全。也许像这样:'protected virtual void OnItemAdded(EventArgs e){var temp = ItemAdded;如果(temp!= null){temp(this,e);}}' – YD4

+0

它如何使事件处理程序在主线程上运行? –