BackgroundWorker如何从外部类报告进度?

5

我有一个工作解决方案,可以向应用程序的主窗体上的进度条和标签报告进度和文本。现在我已经将我的worker方法移动到一个类中,以便它们可以跨多个表单进行访问等。

在worker方法中有BW.ReportProgress()语句,它们将进度和文本推回到主窗体中的BackgroundWorker。

为了更好地了解,这里是文件布局:

MainScreen.cs

List repSelected = new List();
XMLandRar xXMLandRar = new XMLandRar();

private void Rarbtn_Click(object sender, EventArgs e)
        {
            GetReps();

            //Run worker
            if (!CreateRarBW.IsBusy)
            {
                CreateRarBW.RunWorkerAsync();
            }
        }

//Worker
private void CreateRarBW_DoWork(object sender, DoWorkEventArgs e)
{
    xXMLandRar.RarFiles(repSelected);
}

//Progress reporting
private void CreateRarBW_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    progBar.Value = e.ProgressPercentage;
    Statuslbl.Text = e.UserState.ToString();
}

我刚刚创建了一个包含所有工作方法的新类,并将进度推送到主窗体。

XMLandRar.cs

public class XMLandRar
{
    public void RarFiles(List repSelected)
    {
        int step = 100 / repSelected.Count();
        int i = 0;
        //Iterate through list and run rar for each
        foreach (string rep in repSelected)
        {
            CreateRarBW.ReportProgress(i, "Raring files for " + rep);
            DirectoryExists(rep);
            ProcessRunner(rep);
            i += step;
            CreateRarBW.ReportProgress(i, "Raring files for " + rep);
        }
    }
}

我遇到的问题是在 XMLandRar 类中,CreateRarBW 无法被识别(显然) - 我该如何在应用程序主屏幕中向 BW 发出 ReportProgress 调用?

3个回答

9
在你的 XMLandRar 类中创建一个事件,供其他对象订阅。
这样,XMLandRar 类就不需要知道或关心 UI 或进度条,它只关心发送消息是否被监听。而且还可以有多个订阅者(比如说如果你想报告给后台工作器和日志,可能会有多个订阅者)。
示例:
private void Rarbtn_Click(object sender, EventArgs e)
{
    GetReps();

    //Run worker
    if (!CreateRarBW.IsBusy)
    {
        // This should be done once, maybe in the contructor. Bind to new event.
        xXMLandRar.ReportProgress += new EventHandler<XMLandRar.ProgressArgs>(xXMLandRar_ReportProgress);

        CreateRarBW.RunWorkerAsync();
    }
}

protected void xXMLandRar_ReportProgress(object sender, XMLandRar.ProgressArgs e)
{
    // Call the UI backgroundworker
    CreateRarBW.ReportProgress(e.Percentage, e.Message);
}

public class XMLandRar
{
    // Event handler to bind to for reporting progress
    public EventHandler<ProgressArgs> ReportProgress;

    // Eventargs to contain information to send to the subscriber
    public class ProgressArgs : EventArgs
    {
        public int Percentage { get; set; }
        public string Message { get; set; }
    }

    public void RarFiles(List repSelected)
    {
        int step = 100 / repSelected.Count();
        int i = 0;
        //Iterate through list and run rar for each
        foreach (string rep in repSelected)
        {
            // Report progress if somebody is listening (subscribed)
            if (ReportProgress != null)
            {
                ReportProgress(this, new ProgressArgs { Percentage = i, Message = "Raring files for " + rep });
            }

            DirectoryExists(rep);
            ProcessRunner(rep);
            i += step;

            // Report progress if somebody is listening (subscribed)
            if (ReportProgress != null)
            {
                ReportProgress(this, new ProgressArgs { Percentage = i, Message = "Raring files for " + rep });
            }
        }
    }
}

正是我想要的,加一! - Myles Gray
当然,这可以进行一些优化和扩展,但你已经掌握了基本思路。=) - Mario S

5

DoWork回调函数中的sender对象是调用此回调函数的BackgroundWorker实例。

这使得你可以使用该实例并将其添加到你的新XMLandRar类中。

private void CreateRarBW_DoWork(object sender, DoWorkEventArgs e)
{
    var worker = sender as BackgroundWorker.
    xXMLandRar.RarFiles(repSelected, worker);
}

XMLandRar.cs

public class XMLandRar
{
    public void RarFiles(List repSelected, BackgroundWorker worker)
    {
    // ...
    }
}


或者你可以将BackgroundWorker实例设置为XMLandRar的类属性。

public class XMLandRar
{
    protected BackgroundWorker mWorker;

    public XMLandRar(BackgroundWorker worker) {
        mWorker = BackgroundWorker;
    }


    public void RarFiles(List repSelected)
    {
        // Do something with {mWorker}
    }
}
或者,正如评论中所提到的那样,可以在XMLandRar类中使用事件。 XMLandRar.cs
public class XmlandRarCompletedEventArgs : EventArgs
{
    public readonly bool Finished;
    public readonly bool Canceled;

    public XmlandRarCompletedEventArgs(bool finished)
    {
        Finished = finished;
        Canceled = !finished;
    }    

}public class OnXmlandRarUpdateEventArgs : EventArgs
{
    public readonly int Percentage;
    public readonly string Message;

    public XmlandRarCompletedEventArgs(int perc) :
        this(perc, "") {
    }   

    public XmlandRarCompletedEventArgs(int perc, string message)
    {
        Percentage = perc;
        Message = message;
    }    

}

public delegate void OnXmlandRarDoWorkHandler(object o);
public delegate void OnXmlandRarUpdateHandler(object o, OnXmlandRarUpdateEventArgs args);
public delegate void OnXmlandRarCompleteHandler(object o, XmlandRarCompletedEventArgs args);

public class XMLandRar
{
    public event OnXmlandRarDoWorkHandler OnDoWork;
    public event OnXmlandRarUpdateHandler OnUpdate;
    public event OnXmlandRarCompletedHandler OnComplete;

    public void RarFiles(List repSelected)
    {
        TriggerDoWork();

        int step = 100 / repSelected.Count();
        int i = 0;
        //Iterate through list and run rar for each
        foreach (string rep in repSelected)
        {
            TriggerUpdate(i, "Raring files for " + rep);
            DirectoryExists(rep);
            ProcessRunner(rep);
            i += step;
            TriggerUpdate(i, "Raring files for " + rep);
        }

        TriggerComplete(true);
    }


    private void TriggerDoWork() 
    {
        if (OnDoWork != null) {
            OnDoWork(this);
        }
    }

    private void TriggerUpdate(perc) {
    }
        if (OnUpdate != null) {
            OnUpdate(this, new OnXmlandRarUpdateEventArgs(perc));
        }

    private void TriggerUpdate(perc, string message) 
    {
        if (OnUpdate != null) {
            OnUpdate(this, new OnXmlandRarUpdateEventArgs(perc, message));
        }
    }

    private void TriggerComplete(bool finished)
    {
        if (OnComplete != null) {
            OnComplete(this, new XmlandRarCompletedEventArgs(finished));
        }
    }
}

用法:

private void CreateRarBW_DoWork(object sender, DoWorkEventArgs e)
{
    var worker = sender as BackgroundWorker;
    // Attach events to class
    xXMLandRar.OnDoWork += delegate(object o) {
        // ...
    };
    xXMLandRar.OnUpdate += delegate(object o, OnXmlandRarUpdateEventArgs args) {
        // ...
    };
    xXMLandRar.OnComplete += delegate(object o, XmlandRarCompletedEventArgs args) {
        // ...
    };
    xXMLandRar.RarFiles(repSelected, worker);
}

希望没有错别字,因为我在办公室。
希望没有错别字,因为我在办公室。

@HenkHolterman - 能否请您详细说明一下?您的意思是,为了成为一个适当的可重用类,RarFiles不能知道GUI,因为那会使它特定于该情况? - Myles Gray
@HenkHolterman 所以我真正需要做的是分离 GUI 修改代码,将其放在主窗体中,并且只在类中具有通用报告更新事件/回调,任何表单/CLI/页面都可以侦听并以自己的方式处理? - Myles Gray
谢谢@GodLesZ - 不错的解决方案,我相信我会用一些片段来完成等等 +1。 - Myles Gray

0

我已经修复了提交的代码中的错误并进行了清理... 这是一个可行的示例,将有助于那些可能无法理解原始代码的人... 尽管我想说,在清理和增强后,代码的意图和功能非常出色。

这是一段工作代码,可以帮助你开始使用背景工作线程来处理任何你需要的事情。

只需修改这个方法 -

    public void RarFiles(List<string> repSelected)

根据您需要完成任何工作。您还需要修改计划使用的参数... 例如,您可能需要一个DataTable或一些自定义对象... 您可以修改

     public class OnXmlandRarUpdateEventArgs : EventArgs

根据您的需求,这样当您收到回调时,就可以使用对这些项目所做更改来更新主UI表单。

您可能需要进行一些微调,但是您明白我的意思。

这是表单代码。不要忘记在表单上创建一个按钮...

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;

    namespace ThreadSample
    {
        public partial class Form1 : Form
        {
            List<string> repSelected = new List<string>();
            XMLandRar xXMLandRar = new XMLandRar();
            BackgroundWorker CreateRarBW = new BackgroundWorker();
            public Form1()
            {
                InitializeComponent();
                repSelected = new List<string> { "asdf", "asdfsd", "h;ljj" };
                CreateRarBW.DoWork += new DoWorkEventHandler(CreateRarBW_DoWork);
            }

            private void Rarbtn_Click(object sender, EventArgs e)
            {
                //GetReps();

                //Run worker
                if (!CreateRarBW.IsBusy)
                {
                    // This should be done once, maybe in the contructor. Bind to new event.
                    xXMLandRar.ReportProgress += new EventHandler<XMLandRar.ProgressArgs>(xXMLandRar_ReportProgress);

                    CreateRarBW.RunWorkerAsync();
                }
            }

            protected void xXMLandRar_ReportProgress(object sender, XMLandRar.ProgressArgs e)
            {
                // Call the UI backgroundworker
                CreateRarBW.ReportProgress(e.Percentage, e.Message);
            }

            //private void CreateRarBW_DoWork(object sender, DoWorkEventArgs e)
            //{
            //    var worker = sender as BackgroundWorker;
            //    xXMLandRar.RarFiles(repSelected, worker);
            //}


            private void CreateRarBW_DoWork(object sender, DoWorkEventArgs e)
            {
                var worker = sender as BackgroundWorker;
                // Attach events to class
                xXMLandRar.OnDoWork += delegate(object o)
                {
                    // ...
                    MessageBox.Show("Hey ... Something is going on over there in the classLib .. " + o);
                };
                xXMLandRar.OnUpdate += delegate(object o, OnXmlandRarUpdateEventArgs args)
                {
                    // ...
                    //foreach (object oo in args)
                    {
                        MessageBox.Show("Hey ... Something is going on over there in the classLib .. Message is " + args.Message + " and Percentage is " + args.Percentage);
                    }
                };
                xXMLandRar.OnComplete += delegate(object o, XmlandRarCompletedEventArgs args)
                {
                    MessageBox.Show("Hey ... Something is going on over there in the classLib .. Canceled is " + args.Canceled + " and Finished is " + args.Finished);
                    // ...
                };
                xXMLandRar.RarFiles(repSelected);//, worker);
            }
        }
    }

这是类代码。您可以在当前项目中创建一个类...请记住,CreateRarBW对象是BackGroundWorker实例...(上面没有包含...)
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.IO;
    using System.Diagnostics;
    using System.Threading;

    namespace ThreadSample
    {
        public class XmlandRarCompletedEventArgs : EventArgs
        {
            public readonly bool Finished;
            public readonly bool Canceled;

            public XmlandRarCompletedEventArgs(bool finished)
            {
                Finished = finished;
                Canceled = !finished;
            }
        }

        public class OnXmlandRarUpdateEventArgs : EventArgs
        {
            public readonly int Percentage;
            public readonly string Message;


            public OnXmlandRarUpdateEventArgs(int perc) : this(perc, "")
            {

            }   

            public OnXmlandRarUpdateEventArgs(int perc, string message)
            {
                Percentage = perc;
                Message = message;
            }

        }

        public delegate void OnXmlandRarDoWorkHandler(object o);
        public delegate void OnXmlandRarUpdateHandler(object o, OnXmlandRarUpdateEventArgs args);
        public delegate void OnXmlandRarCompleteHandler(object o, XmlandRarCompletedEventArgs args);

        public class XMLandRar      // : BackgroundWorker
        {

            // Event handler to bind to for reporting progress
            public EventHandler<ProgressArgs> ReportProgress;

            // Eventargs to contain information to send to the subscriber
            public class ProgressArgs : EventArgs
            {
                public int Percentage { get; set; }
                public string Message { get; set; }
            }

            public event OnXmlandRarDoWorkHandler OnDoWork;
            public event OnXmlandRarUpdateHandler OnUpdate;
            public event OnXmlandRarCompleteHandler OnComplete;

            public void RarFiles(List<string> repSelected)
            {
                TriggerDoWork();

                int step = 100 / repSelected.Count();
                int i = 0;
                //Iterate through list and run rar for each
                foreach (string rep in repSelected)
                {
                    TriggerUpdate(i, "Raring files for " + rep);
                    //DirectoryExists(rep);
                    //ProcessRunner(rep);
                    i += step;
                    TriggerUpdate(i, "Raring files for " + rep);
                }

                TriggerComplete(true);
            }


            private void TriggerDoWork()
            {
                if (OnDoWork != null)
                {
                    OnDoWork(this);
                }
            }

            private void TriggerUpdate(int perc)
            {

                if (OnUpdate != null)
                {
                    OnUpdate(this, new OnXmlandRarUpdateEventArgs(perc));
                }
            }

            private void TriggerUpdate(int perc, string message)
            {
                if (OnUpdate != null)
                {
                    OnUpdate(this, new OnXmlandRarUpdateEventArgs(perc, message));
                }
            }

            private void TriggerComplete(bool finished)
            {
                if (OnComplete != null)
                {
                    OnComplete(this, new XmlandRarCompletedEventArgs(finished));
                }
            }
        }

    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接