views:

926

answers:

2

This may seem like a somewhat contrived example, but I'm left scratching my head.

Ok, I have a console app that instantiates a WindowsForm and calls a method called DoSomeWork() on the form.

class Program
  { 
    static void Main(string[] args)
    {
      Form1 form = new Form1();         
      form.DoSomeWork();   
    }
  }

Form1 looks like this...

public partial class Form1 : Form
  {
    public Form1()
    {
      InitializeComponent();
    }

    public void DoSomeWork()
    {
      OuterClass outerClass = new OuterClass();
      outerClass.DoSomeWork();
    }    
  }

Outer class, in turn, looks like this...

public class OuterClass
  {
    public void DoSomeWork()
    {
      InnerClass innerClass = new InnerClass();
      innerClass.DoSomeWork();
    }
  }

And finally InnerClass looks like this...

public class InnerClass
  {
    private BackgroundWorker _backgroundWorker = new BackgroundWorker();

    public InnerClass()
    {
      _backgroundWorker.WorkerReportsProgress = true;
      _backgroundWorker.DoWork += new DoWorkEventHandler(BackgroundWorker_DoWork);
      _backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(BackgroundWorker_ProgressChanged);
    }

    void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
      int i = 0; //I've placed a break point here. But it's never hit
    }

    void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
      BackgroundWorker worker = sender as BackgroundWorker;

      worker.ReportProgress(42);
    }

    public void DoSomeWork()
    {
      _backgroundWorker.RunWorkerAsync();
    }
  }

For a reason unknown (to me), the BacgroundWorker in InnerClass never seems to fire the ProgressChanged event. If I replace

Form1 form = new Form1();

with

OuterClass outerClass = new OuterClass()

in class Program, it works fine. So why is that my events don't fire when I'm calling the same methods through a Form?

Thanks!

EDIT: I seemed to be throwing people off by leaving the ProgressChanged event handler as throwing a NotImplementedException, so I've removed it for clarity.

+2  A: 

Did you actually throw NotImplementedException(); in the handler? or you're just mocking this up quick and forgot to remove it?

My guess would be that it is related to different thread apartment models being utilized.

From my experience if a single-thread-apartment non-UI thread throws an exception outside of the main UI thread, that thread will simply dies without any warning.

Windows Forms require a different apartment model than Console applications if I remember correctly. That could be the source of the problem.

I could be wrong but that should give some pointers.

chakrit
Yes, I was mocking the app up thats why I left the NotImplementedException in there. In any case, it never gets thrown since the ProgressChanged event never fires. But you've given me something to work with at least...thanks!
Hovito
Ah, but how do you *know* the ProgressChanged event never fires? His point is that the NotImplementedException might well be thrown, but ignored. Add a Debug.Print in there and see if you see it.
Kyralessa
Oh, I understand now...well I added the Debug code and still, no dice. I need to read up on using background threads inside Windows Forms apps
Hovito
+5  A: 

You forgot to start a message loop, calling Application.Run() is required. Without a message loop, the BackgroundWorker events cannot work. To fix:

static void Main(string[] args)
{
  Application.Run(new Form1());   
}

Call DoSomeWork() in the form's constructor or it's Load event.

Hans Passant
Yes, at last :) Thankyou. That was the problem. Much appreciated!
Hovito