【问题标题】:Writing a method that reports progress编写一个报告进度的方法
【发布时间】:2012-11-22 20:56:07
【问题描述】:

我正在编写一个在库中执行特定操作的类。但是操作很繁琐,我希望能够在该类中找出方法的进度,以便在 WinForms 应用程序中使用它来报告进度。

我打算在我的 WinForms 应用程序的另一个线程上运行我的类,我希望该类与 WinForms 应用程序的关注点分开,并且我不想将它绑定到除它之外的任何特定内容可以。

在库类中实现进度报告机制的最佳方式是什么?

在类中以某种方式有一个进度变量,并在我的 WinForms 应用程序中添加一个事件侦听器是个好主意吗?如果是,我该怎么做?

编辑:我以前使用过BackgroundWorker 类,但我的问题是我不希望我的库类涉及任何多线程操作。所以我不想在库类中调用ReportProgress,我想(也许)在类中有一个包含当前进度的变量,并且我希望UI线程以某种方式“订阅”它。不过,我不知道这是否是一种很好的设计方式。

【问题讨论】:

  • 有很多不同的方法可以解决这个问题,但是您现有的代码是什么样的......?如果你能提供你迄今为止尝试过的东西会有所帮助..
  • 目前我没有太多代码。我想在编写课程之前先了解如何进行。如果您能指出解决此问题的一些众所周知的方法,我将不胜感激。

标签: c# multithreading progress-bar progress


【解决方案1】:

查看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。这是一种依赖注入的形式,应该有意义地允许您的对象报告进度,同时避免对线程库的特定依赖。

【讨论】:

    【解决方案2】:

    在这里你可以做 2 种不同的方式,我将在下面发布这两个选项来帮助你指出正确的方向

    应该在另一个线程上执行此操作,然后从该线程更新您的 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()。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-19
      相关资源
      最近更新 更多