1

我是 C# 的新手,我正试图围绕面向对象的编程来思考。这是我想要完成的事情:

我有一个带有 Form1 的 Windows 窗体应用程序和一个名为 connect 的单独类(相同的命名空间)。

我知道在执行大量代码时使用后台工作程序是一种很好的做法(以免冻结 UI)。所以我在 Form1 中创建了一个后台工作者和一个 progresschanged 句柄。我试图找到如何在单独的连接类中触发progresschange。在 Form1 的 progresschange 块中,我有一个大小写/开关,它确定屏幕上显示的文本。

解决这个问题的最佳方法是什么?我应该将后台工作人员传给其他班级吗?

4

2 回答 2

5

您还可以将 BackgroundWorker 放在 Connect 类中。然后,在此类中,您可以创建事件以将进度和完成情况报告回调用表单。

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";
    }
}
}

然后在您的表单上,您只需处理事件。

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();
        }
    }        
}
}

请注意,BackgroundWorker.ReportProgress() 方法的第二个参数(UserState)可以传递任何对象。它不一定是字符串。例如,如果您从数据库中检索一行/多行,则可以通过此方法将该行传递回用户界面。BackgroundWorker.DoWork 方法的 e.Result 也是如此。

埃里克

于 2012-10-21T05:34:18.420 回答
2

您可以将连接类的步骤分解为单独的方法并按如下顺序调用它们。您不必从连接类对象触发 progresschanged 事件。

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.");
}
于 2012-10-21T04:33:13.900 回答