如何在每个循环周期更新进度条一步? C#

发布于 2024-09-19 10:15:18 字数 250 浏览 1 评论 0原文

使用 C#、Windows 窗体创建 .net 应用程序。如何在 100 个循环的每个循环中更新进度条 1 步? (我正在循环中处理 Excel 工作表。) 进度条控件位于 UI 类中,该类连接到控制器类,该控制器类连接到自定义类 (MVC 模式)。循环位于自定义类中。 我是否需要在每个方法中一路向下发送 UI 类实例,还是有更好的方法?

现在,进度条在循环结束后更新。 Application.doevents 和 .update 或 .refresh 不起作用。

Creating a .net application in C#, windows forms. How do I update the progress bar 1 step every cycle of a 100 cycle loop?
(I’m processing an excel sheet in the loop.)
The progress bar controls are in the UI class which connects to the controller class which connects to a custom class
(MVC pattern). The loop is in the custom class.
Do I need to send the UI class instance all the way down in each method or is there a better way?

Right now the progress bar updates after the loop finishes. Application.doevents and .update or .refresh don’t work.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

软的没边 2024-09-26 10:15:18

假设下面是您的类负责使用其中的循环进行工作。添加一个事件来表明您的进度。然后从您的 UI 中简单地处理该事件并相应地更新进度条。

sealed class Looper
{
    public event EventHandler ProgressUpdated;

    private int _progress;
    public int Progress
    {
        get { return _progress; }
        private set
        {
            _progress = value;
            OnProgressUpdated();
        }
    }

    public void DoLoop()
    {
        _progress = 0;
        for (int i = 0; i < 100; ++i)
        {
            Thread.Sleep(100);
            Progress = i;
        }
    }

    private void OnProgressUpdated()
    {
        EventHandler handler = ProgressUpdated;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }
}

您可以通过将 BackgroundWorker 作为 UI 的一部分来实现此目的,在 backgroundWorker.DoWork 事件中调用 looper.DoLoop()。然后,在 looper.ProgressUpdated 事件的处理程序中,您可以调用 backgroundWorker.ReportProgress 来增加 UI 线程中的进度条。

请注意,将进度本身包含在 ProgressUpdated 事件携带的信息中可能更有意义(我只是不想编写一个从 EventArgs 派生的新类> 来说明这一点;无论如何你可能已经明白了)。

另请注意,除非您在与 UI 线程不同的线程上使用循环执行代码,否则上述内容实际上没有任何意义。否则,无论如何,您的所有工作都会在下一次 UI 刷新之前完成,因此进度条不会提供任何值(循环完成时它只会从 0 变为 100)。

只是一个如何实现此类事情的示例。

Say the below is your class responsible for doing the work with the loop in it. Add an event to indicate your progress. Then from your UI simply handle that event and update the progress bar accordingly.

sealed class Looper
{
    public event EventHandler ProgressUpdated;

    private int _progress;
    public int Progress
    {
        get { return _progress; }
        private set
        {
            _progress = value;
            OnProgressUpdated();
        }
    }

    public void DoLoop()
    {
        _progress = 0;
        for (int i = 0; i < 100; ++i)
        {
            Thread.Sleep(100);
            Progress = i;
        }
    }

    private void OnProgressUpdated()
    {
        EventHandler handler = ProgressUpdated;
        if (handler != null)
        {
            handler(this, EventArgs.Empty);
        }
    }
}

You might implement this by having a BackgroundWorker as part of your UI, where in the backgroundWorker.DoWork event you call looper.DoLoop(). Then in your handler for the looper.ProgressUpdated event you can call backgroundWorker.ReportProgress to increment your progress bar from the UI thread.

Note that it would probably make more sense to include the progress itself in the information carried by your ProgressUpdated event (I just didn't feel like writing out a new class deriving from EventArgs to illustrate this; you probably get the picture anyway).

Also note that the above really doesn't make sense unless you're executing your code with the loop on a separate thread from the UI thread. Otherwise, all of your work is getting done before the next UI refresh anyway, so your progress bar would not be providing any value (it would just go from 0 to 100 when the loop completed).

Just an example of how this sort of thing can be achieved.

兔姬 2024-09-26 10:15:18

我通常有一个类对 UI 进行调用检查。用户界面-> “UpdaterClass”->其他类。

Updater 类具有预定义的方法和对 UI 控件的引用。所以我调用 Updater.StepProgressBar() 来步进 UI 进度条。我将 Updater 类引用传递给任何需要直接更新 UI 的类。

这样,来自不同线程的所有 UI 更新都由一个类处理。这不是最通用的实现方式,但它永远不会失败。

伪代码示例:

class Updater()
{

  public ProgressBar pb;

  delegate void UpdateProgressBar();

  public StepProgressBar()
  {
     if(pb.InvokeRequired)
     {
          BeginInvoke(new UpdateProgressBar(this.StepProgressBar);
     }
     else
     {
          pb.Step();
      }
   }

}

类似的东西。

I usually have one class that does the invocation checks on the UI. UI -> "UpdaterClass" -> other class.

The Updater class has predefined methods and references to the UI controls. So Updater.StepProgressBar() is what I call to step the UI progress bar. I pass the Updater class reference to any class that is going to need to update the UI directly.

This way, all UI updates from different threads are handled by one class. Not the most generic way to impliment it, but it never fails.

Example psuedocode:

class Updater()
{

  public ProgressBar pb;

  delegate void UpdateProgressBar();

  public StepProgressBar()
  {
     if(pb.InvokeRequired)
     {
          BeginInvoke(new UpdateProgressBar(this.StepProgressBar);
     }
     else
     {
          pb.Step();
      }
   }

}

Something like that.

您可以使用代表。当您的后台进程创建自定义类时,绑定从自定义类调用的委托来报告更新。然后,您可以在 UI 层中对该调用做出反应,并从那里更新进度条。

例如(警告,伪代码):

MyCustomClass class = new MyCustomClass();
class.ProgressUpdated += (s,e)=>{ /* update UI */};
class.StartLoop();

You could use a delegate. When your background process creates the custom class, tie on a delegate that gets called from the custom class to report update. Then you can react to that call in the UI layer and update the progress bar from there.

e.g. (warning, psuedocode):

MyCustomClass class = new MyCustomClass();
class.ProgressUpdated += (s,e)=>{ /* update UI */};
class.StartLoop();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文