简体   繁体   中英

BackgroundWorker ProgressChanged in a form being triggered from a separate class

I'm new to C# and am trying to wrap my mind around object oriented programming. Here's what I am trying to accomplish:

I've got a Windows Form application with Form1 and a separate class called connect (same namespace).

I understand that it is good practice to use backgroundworkers when executing lengthy amounts of code (so as not to freeze the UI). So I've created a background worker in Form1 and a progresschanged handle. I'm trying to find how in the separate connect class I can trigger a progresschange. In the progresschange block in Form1 I have a case/switch which determines what text shows on the screen.

What is the best way to approach this? Shall I pass the backgroundworker to the other class?

You could also place your BackgroundWorker in your Connect class. In this class you could then create events to report the progress and completion back to the calling form.

using System;
using System.ComponentModel;

namespace WindowsTest
{
public class Connect
{
    BackgroundWorker bw;
    public Connect()
    {
        bw = new BackgroundWorker();
        bw.WorkerSupportsCancellation = true;
        bw.WorkerReportsProgress = true;
        bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
        bw.DoWork +=new DoWorkEventHandler(bw_DoWork);
        bw.ProgressChanged += new ProgressChangedEventHandler(bw_ProgressChanged);
    }

    public delegate void ProgressChangedHandler(Object sender, ProgressChangedEventArgs e);
    public event ProgressChangedEventHandler ProgressChanged;
    protected void RaiseProgressChangedEvent(ProgressChangedEventArgs e)
    {
        if (ProgressChanged == null)
        {
            return;
        }
        ProgressChanged(this, e);
    }

    public delegate void WorkCompleteEventHandler(Object sender, RunWorkerCompletedEventArgs e);
    public event WorkCompleteEventHandler WorkComplete;
    protected void RaiseWorkCompleteEvent(RunWorkerCompletedEventArgs e)
    {
        if (WorkComplete == null)
        {
            return;
        }
        WorkComplete(this, e);
    }

    public void Cancel()
    {
        if (bw.IsBusy)
        {
            bw.CancelAsync();            
        }
    }

    public void BeginLongRunningProcess()
    {
        bw.RunWorkerAsync();
    }

    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        RaiseWorkCompleteEvent(e);
    }

    private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        RaiseProgressChangedEvent(e);
    }

    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        if (ConnectToServer())
        {
            bw.ReportProgress(0, "Connected to server");
            e.Result = LongRunningProcess();
            if (e.Result.ToString() == "Cancelled")
            {
                e.Cancel = true;
                return;
            }
        }
        else
        {
            //Connection failed
            e.Cancel = true;    
        }
    }

    private bool ConnectToServer()
    { 
        //Attempt connection
        return true;
    }

    private string LongRunningProcess()
    {
        int recordCount = 250;
        for (int i = 0; i <= recordCount; i++)
        {
            if (bw.CancellationPending)
            {
                return "Cancelled";
            }
            double progress = ((double)i / (double)recordCount) * 100;
            bw.ReportProgress((int)progress , "Running Process");
            System.Threading.Thread.Sleep(25);
        }
        return "The result is 2";
    }
}
}

Then on your form you simply handle the events.

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

    Connect connect;

    private void btnConnect_Click(object sender, EventArgs e)
    {
        connect = new Connect();
        connect.ProgressChanged += new ProgressChangedEventHandler(connect_ProgressChanged);
        connect.WorkComplete += new Connect.WorkCompleteEventHandler(connect_WorkComplete);
        connect.BeginLongRunningProcess();
    }

    private void connect_WorkComplete(object sender, RunWorkerCompletedEventArgs e)
    {
        if (e.Cancelled)
        {
            lblStatus.ForeColor = Color.Red;
            lblStatus.Text = string.Format("Status: {0}", "User Cancelled!");
            return;
        }

        if (e.Error != null)
        { 
            //Process exception       
            lblStatus.Text = string.Format("Status: {0}", "Error!");
            lblStatus.ForeColor = Color.Red;
            return;
        }

        lblStatus.Text = string.Format("Status: Complete. {0}", e.Result);
    }

    private void connect_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;
        lblStatus.Text = string.Format("Status: {0}", e.UserState.ToString());
    }

    private void btnCancel_Click(object sender, EventArgs e)
    {
        if (connect != null)
        {
            connect.Cancel();
        }
    }        
}
}

Note that the second parameter (UserState) of the BackgroundWorker.ReportProgress() method can pass any object. It doesn't have to be a string. For example if you retrieved a row/rows from a database, you could pass the row back to the user interface through this method. The same is true for the e.Result of the BackgroundWorker.DoWork method.

Eric

You could break your steps of the connect class into separate methods and invoke them sequentially as below.You dont have to trigger the progresschanged event from connect class object.

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
     ConnectClass conObject= new ConnectClass();
     backgroundWorker.ReportProgress(30, "Connecting ...");
     conObject.Connect();
     backgroundWorker.ReportProgress(30, "Connected."+"\n Executing query");
     conObject.Execute();
     backgroundWorker.ReportProgress(40, "Execution completed.");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM