Check before proceeding if the task in BackgroundWorker has completed I have a Login Form (which has a label that will show status of background process, username and password text boxes, Login and Cancel buttons) along with that I have a background worker to do some time taking task (in the meanwhile when Login Form loads and user provide details in text boxes).

Background task keep running while the user will be providing username and password on Login Form. As soon as the user hits the Login button I want to check the status if the background process has completed successfully and then only it should proceed (launch the MainForm)

Otherwise should pop-up error. Following is what I did to achieve but the 'while()' strategy doesn't look elegant. Is there any more appropriate way?

  public partial class LoginForm : Form
    {
        private static BackgroundWorker bw = new BackgroundWorker();
        private static ManualResetEvent mre = new ManualResetEvent(false);

        enum status
        {
            Blank,
            Success,
            Error
        };

        public LoginForm()
        {
            InterimProceedings();
            InitializeComponent();
        }

        private void InterimProceedings()
        {

            bw.DoWork += new DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += 
            new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);

            if (!bw.IsBusy)
            {
                bw.RunWorkerAsync();
            }
            else
            {
                throw new InvalidOperationException("BackgroundWorker is busy");
            }
        }

        private static void bw_DoWork(object sender, DoWorkEventArgs e)
        {
          //  Time taking task
              mre.Set();
        }

        private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (!(e.Error == null))
            {
                this.lbl_status.Text = "Cannot proceed, Error occured";
                appStatus = status.Error;
            }
            else
            {
                this.lbl_status.Text = "Good to go...";
                appStatus = status.Success;
            }
        }

        private void btn_login_Click(object sender, EventArgs e)
        {
            mre.WaitOne();

            if(appStatus == status.Success)
            {
                // Proceed with intended work
            }

            else
            {
                // Pop-up error occurred
            }
        }
}
You can use ManualResetEvent to wait until background work is done. So, you can define in LoginForm as:

private static ManualResetEvent mre = new ManualResetEvent(false);


When background work is completed, you should change the state of mre from the thread method bw_DoWork and update appStatus:

mre.Set();


btn_login_Click should wait for mre instead of while loop:

mre.WaitOne();


The complete code:

public partial class LoginForm : Form
{
    private static BackgroundWorker bw = new BackgroundWorker();
    private static ManualResetEvent mre = new ManualResetEvent(false);

    enum status
    {
        Blank,
        Success,
        Error
    };

    public LoginForm()
    {
        InterimProceedings();
        InitializeComponent();
    }

    private void InterimProceedings()
    {
        bw.DoWork += new DoWorkEventHandler(bw_DoWork);
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);

        if (!bw.IsBusy)
        {
            bw.RunWorkerAsync();
        }
        else
        {
            throw new InvalidOperationException("BackgroundWorker is busy");
        }
    }

    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
      //  Time taking task
      //  Update appStatus
      appStatus = status.Success;
      mre.Set();
    }

    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if (!(e.Error == null))
        {
            this.lbl_status.Text = "Cannot proceed, Error occured";
            appStatus = status.Error;
        }
        else
        {
            this.lbl_status.Text = "Good to go...";
            appStatus = status.Success;
        }
    }

    private void btn_login_Click(object sender, EventArgs e)
    {
        mre.WaitOne();

        if(appStatus == status.Success)
        {
            // Proceed with intended work
        }

        else
        {
            // Pop-up error occurred
        }
    }
}




The check against e.Error on bw_RunWorkerCompleted should change for clarity:

if (e.Error == null)
{
    this.lbl_status.Text = "Good to go...";
}
else
{
    this.lbl_status.Text = "Cannot proceed, Error occured";
}




I can't probe this code right now... I hope it's ok.