如何将进度条与函数执行同步? [英] How to sync progress bar with a function execution?

查看:168
本文介绍了如何将进度条与函数执行同步?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 windows 窗体 c# 创建一个更干净"的应用程序,并且想要一个进度条.目前我只是清理临时文件、缓存文件和浏览器垃圾.

I am creating a 'cleaner' application using windows forms c# and want to have a progress-bar. At the moment I am just cleaning temp files, cache files and browser junk.

我有一个进度条:

private System.Windows.Forms.ProgressBar _myProgressBar;

这是我的清理方法:

    private void button1_Click_1(object sender, EventArgs e)
    {
        _myProgressBar.Value = 0;
        ClearCache();
        _myProgressBar.Value = 25;
        ClearCookie();
        _myProgressBar.Value = 50;
        ClearHistory();
        _myProgressBar.Value = 75;
        TempCleaner();
        _myProgressBar.Value = 100;
    }

我希望它在更新进度条的同时执行这 4 个方法(每个方法都需要几秒钟才能完成);但它所做的只是等到他们完成,然后将进度条显示为完成.如何让进度条在完成每个部分时显示进度?

I want it to execute those 4 methods (each of which takes a few seconds to complete) while updating the progress bar as it goes; but all it does is wait until they have finished and then show the progress bar as completed. How can I make the progress bar show the progress as it completes each part?

推荐答案

这是一个复杂的主题,代码示例和您的声誉表明您可能有点缺乏经验;这是一个棘手的组合.但我会尝试回答......(其他读者请记住,我会尽量保持这个答案的简单化).

This is a complicated subject, and the code sample and your reputation indicates that you may be a little inexperienced; which is a tricky combination. But I'm going to try to answer... (other readers please bear in mind I'm going to try to keep this answer simplistic).

它复杂的原因是为了正确地完成它,您将需要使用线程.线程是一个庞大而棘手的话题,即使对于有经验的开发人员来说,它也会引起问题.我不可能希望在这里合理地涵盖所有主题,所以我只会坚持要点.

The reason it's complicated is that in order to do it properly, you're going to need to use threading. Threading is a massive and tricky topic, which causes problems even for experienced developers. I cannot possibly hope to reasonably cover that topic all here, so I'm just going to stick to the key points.

当您的 WinForms 应用程序运行时,除非您特别安排它,否则您的代码将运行在所谓的用户界面线程"(UI 线程")上.理想情况下,应该让该线程处理窗口上的事件(如移动、调整大小、鼠标点击等).如果你想做任何需要时间的事情(比如上面点击"方法的内容),那么你需要在后台线程上执行该功能(而不是直接在方法中,正如你在上面所做的那样)

When your WinForms application is running, unless you arrange it specially, your code will be running on what can be called the "user interface thread" ("UI thread"). Ideally, that thread should be left to do things like processing events on the window (like moving, resizing, mouse clicks, etc). If you want to do anything which is going to take time (like the contents of your "Click" method above), then you need to execute that functionality on a background thread (not directly within the method, as you've done above)

您需要知道的是,虽然工作将在后台线程上完成,但对进度条的更改将必须由 UI 线程完成 - 这是强制性的,不允许从后台线程执行此操作.

Something you need to know is that although the work is going to be done on a background thread, the changes to the progress bar will have to be done by the UI thread - this is mandatory, you are not allowed to do it from a background thread.

这里是我提出的解决方案的关键点:

So here are the key points to my proposed solution:

  1. 将代码从 Click 方法移到后台工作器中,并在工作进行时添加来自该工作器的进度通知
  2. 从正确的线程更新进度条

所以我们开始...1) 有很多的方法可以做到这一点.这是一个...将您所有的代码从 Click 事件移动到一个名为BackgroundThread"的方法中,然后修改您的 click 方法,以便您拥有这个...

So here we go... 1) There are lots of ways of doing this. Here's one... move all your code from the Click event into a method called "BackgroundThread", and modify your click method so you have this...

    private void button1_Click_1(object sender, EventArgs e)
    {
        if (_thread == null)
        {
            _thread = new Thread(new ThreadStart(BackgroundThread));
            _thread.IsBackground = true;
            _thread.Start();
        }
    }

    private void BackgroundThread()
    {
        UpdateProgress(0);
        ClearCache();
        UpdateProgress(25);
        ClearCookie();
        UpdateProgress(50);
        ClearHistory();
        UpdateProgress(75);
        TempCleaner();
        UpdateProgress(100);
    }

您需要将_thread"变量声明为表单上的私有成员变量(以防止它被垃圾收集).

You'll need to declare that "_thread" variable as a private member variable on your Form (to prevent it being garbage collected).

现在我要强调但不解决您需要处理的几个问题.由于我们已将代码移至后台线程,因此不会阻止用户多次按下按钮,每次按下按钮都会触发一个新线程(可能不是您想要的).你如何处理这个问题取决于进度条在你的 UI 中的位置,以及你希望人们按下按钮的频率.一个简单(但不完整)的答案是将 Click 方法的内容包含在if(_thread==null)"中(如上所示),这意味着该按钮仅在您第一次单击时起作用.

Now I'm going to highlight but not solve a couple of problems that you will need to deal with. Since we have moved the code onto a background thread, there will be nothing stopping the user pressing the button lots of times, each of which would fire off a new thread (probably not what you want). How you deal with that problem depends on how the progress bar sits in your UI, and how often you want people to press the button. A simple (but incomplete) answer would be to wrap the contents of the Click method in "if(_thread==null)" (as shown above), meaning that the button would only work the first time you clicked it.

另一个问题是如果您希望后台线程停止正在执行的操作(例如用户想要关闭应用程序),则通知您的后台线程.正如我所说,这是一个很大的话题,我不会在这里讨论.

The other problem is notifying your background thread if you wanted it to stop what it was doing (e.g. user wants to close the application). As I've said, it's a big topic, and I'm not going to get into that here.

3) 上面的代码需要我们编写UpdateProgress方法...

3) The above code needs us to write the UpdateProgress method...

    private void UpdateProgress(int percent)
    {
        RunOnUiThread(() => _myProgressBar.Value = percent);
    }

    private void RunOnUiThread(Action action)
    {
        if (InvokeRequired)
        {
            Invoke(action);
        }
        else
        {
            action();
        }
    }

您一定已经猜到了_myProgressBar.Value = percent";但其余部分可能看起来很奇怪.RunOnUiThread 方法可在任何 WinForm 窗体或控件上重用,因此您可能希望将其保留在片段中.基本上,无论你给它什么动作,它都会检查它是否不在 UI 线程上(InvokeRequired").我们传递给它一个 lambda 表达式() =>"来做我们需要在 UI 线程上发生的事情.

You will have guessed the "_myProgressBar.Value = percent"; but the rest of it probably looks bizarre. The RunOnUiThread method is reusable on any WinForm Form or Control, so you might like to keep that in a snippet. Basically, whatever action you give it, it will check whether it's on not the UI thread ("InvokeRequired"). We're passing it a lambda expression "() =>" to do what we need to happen on the UI thread.

如果它在错误的线程上,它将调用"该操作(基本上将其排队,以便 UI 线程在有机会时执行它).如果它已经在正确的线程上,那么它只会在同一个线程上执行操作.

If it's on the wrong thread, it will "Invoke" the action (basically queue it up so that the UI thread will do it when it gets the chance). If it was already on the right thread then it will just execute the action on the same thread.

应该可以.

这篇关于如何将进度条与函数执行同步?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆