Execute a method in main thread from event handler

backgroundworker, c#, events, multithreading, winforms

Solution

You are enqueueing items on background thread (DoWork event handler runs on background thread), thus your event raised also in background thread.

Use `InvokeRequired` method to verify if you are on UI thread. And if not, then use `Invoke` to run code on UI thread:

 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();
 }

Another option for you - use `ProgressChanged` event to enqueue items (don't forget to set `WorkerReportsProgress` to true). This event handler runs on UI thread:

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);
}

Problem

I have a custom Queue class inherited from Queue class. It has an event ItemAdded. In the event handler of this event i am executing a method. But it is running other than main thread, though i want it in main thread. I don't know how to do it. Any suggestion ? ``` //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(); } } } ``` Thanks in advance. SKPaul.

Original source