2012-12-04 152 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

它如何使事件處理程序在主線程上運行? –