【问题标题】:How do I set a ProgressBar to increment at each tick of a Timer?如何将 ProgressBar 设置为在 Timer 的每个刻度处递增?
【发布时间】:2012-07-13 18:38:09
【问题描述】:

我有一个简单的表单,它应该启动一个计时器,执行一个耗时的操作,并在该操作工作时以特定间隔更新进度条。现在,耗时操作绑定到SearchButton。但是,进度条没有任何反应,即使耗时的操作(在这种情况下是下载)确实需要几秒钟:

public partial class Form1 : Form
{
    System.Windows.Forms.Timer searchProgressTimer;

    public Form1()
    {
        InitializeComponent();
        this.searchProgressTimer = new System.Windows.Forms.Timer();
    }

    private void InitializeTimer()
    {
        this.searchProgressTimer.Interval = 250;
        this.searchProgressTimer.Tick += new EventHandler(searchProgressTimer_Tick);
    }

    void searchProgressTimer_Tick(object sender, EventArgs e)
    {
        searchProgressBar.Increment(1);
        if (searchProgressBar.Value == searchProgressBar.Maximum)
            this.searchProgressTimer.Stop();
    }

    private void SearchDatabase_Click(object sender, EventArgs e)
    {
        this.searchProgressTimer.Start();

        // Time-consuming operation
        String filename = @"http://www.bankofengland.co.uk/publications/Documents/quarterlybulletin/qb0704.pdf";
        WebClient webClient = new WebClient();
        webClient.DownloadFileAsync(new Uri(filename), @"file.pdf");
        int test;
        for (int i = 0; i < 100000; i++)
            for (int j = 0; j < 100000; j++)
                test = i + j;


        this.searchProgressTimer.Stop();

    }
}

(这些函数的命名有点奇怪,因为实际耗时的操作是数据库搜索,但该代码虽然工作正常,但非常长且涉及)。

调试这段代码只是告诉我SearchButton_Click 事件处理程序正确触发,但代码永远不会跳转到searchProgressTimer_Tick 事件处理程序。有什么想法吗?

【问题讨论】:

  • 我没有看到任何对 InitializeTimer() 的调用
  • searchProgressBar.Incriment(1) 上设置断点。您可以通过单击该行左侧的边距来执行此操作。将出现一个红点,让您知道断点在那里。在调试器中运行它,看看是否命中了断点。

标签: c# winforms


【解决方案1】:

你在这里做的有点令人困惑。假设您实际上是在某处初始化计时器 - 我认为这就是正在发生的事情......

Forms.Timer 类完全在表单的消息循环上运行,因此当函数在该线程上运行时它不能触发。因此,尽管您 Start() 计时器,Click() 函数与计时器在同一线程上运行,因此计时器在该函数返回之前无法触发。但是,在该函数返回您之前Stop() 再次计时器。

也许你想看看Threading.Timer。虽然 - 理想情况下,您正在做的“工作” - 无论是数据库操作还是愚蠢的嵌套 for 循环 - 应该发生在不同的线程上,以便 GUI 的消息循环仍然可以处理。

如果您为此创建了不同的线程,请不要忘记在主 UI 线程上调用任何 UI 更改或对 UI 元素的更改!

【讨论】:

    【解决方案2】:

    所以 1) 我在任何地方都没有看到对 InitializerTimer() 的调用。

    和 2) System.Windows.Forms.Timer 在 UI 线程上引发其滴答事件。您正在执行耗时操作的同一线程。您需要不时将控制权交给消息泵,以便处理偶数。

    【讨论】:

    • 这两个都是问题所在。我更新了我的代码以包含对BackgroundWorker 的调用及其功能。我打算接受你的回答,但我应该编辑我的问题并添加有效的代码吗?
    • 将工作代码添加到问题中将使未来的搜索者更快地获得答案。由你决定。
    【解决方案3】:

    这是因为您的 GUI 更新发生在与数据库操作相同的线程中。数据库操作应该在不同的线程中完成,并调用 GUI 线程通知它更新。看看这个,因为它解释得很好。

    http://www.dotnetperls.com/progressbar

    【讨论】:

    • 如果您在同一个线程中进行耗时的工作,您的进度条将永远无法正常工作。后台工作人员是为这样的任务而设计的。
    【解决方案4】:

    调试此代码只是显示 SearchButton_Click 事件处理程序正确触发,但代码从不跳转到 searchProgressTimer_Tick 事件处理程序。

    尝试将您的 IntializeTimer() 例程移至表​​单的构造函数,因为看起来您从未为计时器连接滴答事件:

    public Form1()
    {
      InitializeComponent();
      this.searchProgressTimer = new System.Windows.Forms.Timer();
      this.searchProgressTimer.Interval = 250;
      this.searchProgressTimer.Tick += new EventHandler(searchProgressTimer_Tick);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-02
      • 2021-07-29
      • 2019-05-06
      相关资源
      最近更新 更多