编写一个报告进度的方法

7
我正在编写一个类,使用库执行某个操作。但是这个操作很繁琐,我想要在该类内部找出方法的进度,以便我可以在WinForms应用程序中报告进度。我计划在WinForms应用程序中的另一个线程上运行我的类,并且不想将其绑定到除它所做的事之外的任何特定内容。在库类中实现进度报告机制的最佳方法是什么?是否有一种好的办法让类中有一个进度变量,并在我的WinForms应用程序中添加事件监听器?如果可以,请问如何实现呢?注:我以前使用过BackgroundWorker类,但是我的问题是我不想让我的库类关注任何多线程操作。因此,我不想在库类中调用ReportProgress,我想(也许)在类中有一个包含当前进度的变量,并希望UI线程以某种方式“订阅”它。不知道这是否是设计它的好方法。

有很多不同的方法可以解决这个问题,但你现有的代码是什么样子的呢?如果你能提供你迄今为止尝试过的内容会更有帮助。 - MethodMan
我现在没有太多的代码。在编写类之前,我想先了解如何进行。如果您可以指导我一些这个问题的众所周知的方法,我将非常感激。 - hattenn
2个回答

4

请看一下BackgroundWorker类,它支持自动跨线程进行进度报告的编组,并且它具有非常简单的事件模型来支持这种功能。

编辑:鉴于您不使用BackgroundWorker直接,您可以创建一个简单的包装器:

// Error checking elided for expository purposes.
public interface IProgressReporter 
{
    void ReportProgress(int progress, object status);
}

public class BackgroundWorkerProgressReporter : IProgressReporter
{
    private BackgroundWorker _worker;
    public BackgroundWorkerProgressReporter(BackgroundWorker worker)
    {
        _worker = worker;
    }

    public void ReportProgress(int progress, object status)
    {
        _worker.ReportProgress(progress, status);
    }
}

然后,修改类的构造函数(或添加属性),使其接受一个IProgressReporter。这是一种依赖注入的形式,应该能够让您的对象在报告进度时避免特定于线程库的依赖关系,并且更易于理解。


1

这里有两种不同的方法,我将发布两个选项以帮助指引您正确的方向

您应该在另一个线程上执行此操作,然后从该线程更新您的UI线程。在UI线程上执行此工作会阻止进一步处理。

如果您无法将此代码移动到UI线程,则始终可以调用Application.DoEvents,但我强烈建议您首先探索这些选项:

第二种选择是这样的:

您需要将数据从一个线程传递到另一个线程。有几种方法可以实现...

首先,您的“后台”线程可以更新某种“CurrentStatus”字符串变量,随着它的进行而更改。然后,您可以在窗体上放置一个计时器,该计时器将获取CurrentStatus变量并使用它来更新标签。

其次,您可以使用标签控件的InvokeRequired属性通过委托从后台线程调用操作到UI线程。例如...

private delegate void UpdateStatusDelegate(string status);
private void UpdateStatus(string status)
{
    if (this.label1.InvokeRequired)
    {
        this.Invoke(new UpdateStatusDelegate(this.UpdateStatus), new object[] { status });
        return;
    }

    this.label1.Text = status;
}

您可以从任何线程(UI 或后台)调用 UpdateStatus() 方法,它会检测是否需要在主 UI 线程上调用操作(如果需要,则执行)。

编辑:要实际设置线程,您可以像这样进行:

    private void StartProcessing()
    {
        System.Threading.Thread procThread = new System.Threading.Thread(this.Process);

        procThread.Start();
    }

    private void Process() // this is the actual method of the thread
    {
        foreach (System.IO.FileInfo f in dir.GetFiles("*.txt"))
        {
            // Do processing
            // Show progress bar
            // Update Label on Form, "f.Name is done processing, now processing..."
            UpdateStatus("Processing " + f.Name + "...");                
        }
    }

然后当用户点击“GO”按钮时,您只需调用StartProcessing()函数即可。


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