0

I'm developing a simple winforms C# application. I want to use Background Workers to display a loading Form on the Top while another Background Worker is making a consult to my WCF server.

My WinForms app works like this: I have a MainForm and lots of UserControls. When I start the app I add a LoginUserControl to the MainForm Controls. When I click the "Login Button" in the LoginUserControl I want to display the Loading Form and Consult the Server at the same time. Later, I need to send to the Loading Background Worker a signal that indicates that the Server Consult Background Worker has finished.

My question is, Should I implement 2 Background Workers for each UserControl that needs a Loading Panel? and How to implement the communication between the Background Workers?

Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325
omaestra
  • 69
  • 1
  • 11
  • this might help - similar sort of thing (splash screen) http://stackoverflow.com/questions/7955663/how-to-build-splash-screen-in-windows-forms-application – owenrumney Jan 23 '14 at 16:38
  • If possible, use `async` and `await` instead of `BackgroundWorker` when dealing with I/O bound operations. – Daniel Mann Jan 23 '14 at 16:38
  • Why two BackgroundWorker? Display the top form, call the one background worker, and in the end the completed event remove the form. – paparazzo Jan 23 '14 at 17:14

2 Answers2

1

Later, I need to send to the Loading Background Worker a signal that indicates that the Server Consult Background Worker has finished.

No you don't need to.

The background worker is exactly what it says: A "worker" that performs a task in the background. The task in your case is the method that communicates with the WCF service that you have. The worker will end when the work is done (or an exception is thrown). So the sequence of events is as follows:

  • Start the worker (must be first if your form is modal)
  • Show the form
  • Listen for the worker RunWorkerCompleted event to hide the form

In fact I have created a form that does something like that, only I don't communicate to a server (doesn't matter actually) and I show a simple progress bar.

public partial class FastForwardForm : Form
{
    private Exception asyncError;

    public event DoWorkEventHandler DoWork
    {
        add { worker.DoWork += value; }
        remove { worker.DoWork -= value; }
    }

    public FastForwardForm()
    {
        InitializeComponent();
    }

    public Exception AsyncError
    {
        get { return asyncError; }
    }

    private void FastForwardForm_Shown(object sender, EventArgs e)
    {
        worker.RunWorkerAsync();
    }

    private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar.Value = e.ProgressPercentage;
        statusLabel.Text = e.UserState.ToString();
    }

    private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Error != null) asyncError = e.Error;
        HideProgressForm();
        worker.Dispose();
    }

    private void HideProgressForm()
    {
        //not actually needed, the callback runs on the UI thread.
        if (InvokeRequired)
        {
            Invoke((Action)HideProgressForm);
            return;
        }
        Close();
    }
}

Please note the following:

  • The worker is a Control subclass, so I added it through the forms editor. That also means that its callbacks are executed on the UI thread and you don't need the if (InvokeRequired) part that I added. Don't ask me why it's there, I missed it after a refactoring :)
  • The form does some of the dirty work for you: starts the worker as soon as it's shown. Stores the exception of the process. Exposes the DoWork so that you can add the background work from anywhere outside the form.
  • The code is not perfect: If you need to reuse the form, you will have to remove worker.Dispose(); and add it to the forms Dispose() method.

Now if you need to show some "waiting" animation in the form, you don't need another worker. You need a Timer control to refresh the animation, but that's another story.

Stelios Adamantidis
  • 1,866
  • 21
  • 36
0

First of all, starting a Form from a BackgroundWorker is a bad idea. This interferes with the single UI thread Windows Forms has.

You'd better open the Form from the UI thread and call Invoke from the BackgroundWorker to close the form.

form.Invoke((MethodInvoker)delegate()
{
    busyForm.Close();
});
Patrick Hofman
  • 153,850
  • 22
  • 249
  • 325