none
Open Form in new Thread using ShowDialog(this)

    Question

  • Hey, I'm having a problem opening a progress bar form over another form in my application. I create the progressBarForm like so:

     

    Code Snippet

    Thread progressThread = new Thread(new ThreadStart(this.ShowProgressForm));

    progressThread.Start();

     

    Code Snippet

    private void ShowProgressForm()

    {

    progressForm = new EthernetProgressForm(25000, "Attemping to connect through Ethernet..."); // 25.5 seconds before, about 21 now

    progressForm.ShowDialog(this); // TODO: invoke with ShowDialog(this)

    }

     

    The problem is that I get the good old cross-thread invoke error. I know how to use cross-thread invokes as I use them in my application, but I don't know exactly how it would be used here. I just tried the following to experiment a little but it didn't work:

     

    Code Snippet

    delegate void ShowProgressFormCallback();

     

    private void ShowProgressForm()

    {

    if (this.InvokeRequired)

    {

    ShowProgressFormCallback spfc = new ShowProgressFormCallback(ShowProgressForm);

    this.Invoke(spfc);

    }

    else

    {

    progressForm = new EthernetProgressForm(25000, "Attemping to connect through Ethernet..."); // 25.5 seconds before, about 21 now

    progressForm.ShowDialog(this); // TODO: invoke with ShowDialog(this)

    }

    }

     

    Not only does it give an error when I try to call progressForm.RequestStop() on my CommConfigForm because it wasn't defined on that thread, it gives the following error on Invoke(spfc):

     

    System.ObjectDisposedException was unhandled
      Message="Cannot access a disposed object.\r\nObject name: 'CommConfigForm'."
      Source="System.Windows.Forms"
      ObjectName="CommConfigForm"

     

    Now the reason I'm doing all this is because if I don't include the (this) in ShowDialog, the CommConfigForm becomes unresponsive but can still be selected and displayed overtop of the progress bar.

    Monday, June 09, 2008 6:26 PM

Answers

  • The "this" argument to ShowDialog() causes the exception.  WF will use it to access the owner form and that will blow.  You can't fix it since that code is located inside System.Windows. Forms.dll.  Just do things the other way around.  It should be your "ethernet code" that should run on a thread, leave both forms on the UI thread.  That prevents your config form from getting unresponsive too.  It must use Invoke or BeginInvoke when it updates any controls.
    Tuesday, June 10, 2008 1:41 AM

All replies

  • You're running into difficulty because you are trying to create a user interface (UI) element (a new form) not from the main application thread (the one that creates your main form). Essentially all changes to the UI have to done through this main thread either directly or through an invoke call.

     

    You might of thought that by creating the dialog in a seperate thread, the dialog would be handled (processed) by the new thread, thus leaving the main thread able to go about it's business. This is not the case. Both forms have to be handled by the main thread.

     

    So, the first step in achieving what you are after is to create your ShowProgressForm from your main form and drop your existing thread code.

     

    In your case you may not need a thread at all because network (ethernet etc) calls can usually be made asychronously, i.e. the process is not blocked while making the network call, instead an event is fired when the event is completed or to report progress.

     

    A System.Windows.Forms.Timer may be useful in this case, to show progress, and as the Tick event handler runs on the main thread, you can update the progress bar without having to worry about using invoke.

     

    Alternatively, if this approach is not usable in your case, you might want to have a look at the BackgroundWorker class which might be just the ticket (check out the example).

     

    You could of course use your own worker thread, where you would do the lenghty task in the background (connecting to network etc) and use invoke to update the progress bar, but you may find the managed approach of BackgroundWorker easier / quicker to implement.

    Monday, June 09, 2008 11:11 PM
  • The "this" argument to ShowDialog() causes the exception.  WF will use it to access the owner form and that will blow.  You can't fix it since that code is located inside System.Windows. Forms.dll.  Just do things the other way around.  It should be your "ethernet code" that should run on a thread, leave both forms on the UI thread.  That prevents your config form from getting unresponsive too.  It must use Invoke or BeginInvoke when it updates any controls.
    Tuesday, June 10, 2008 1:41 AM