2012-07-13 61 views
0

我有一个简单的表单,应该启动一个计时器,执行耗时的操作,并在该操作正在工作时以特定间隔更新进度条。目前,耗时的操作必然会涉及到SearchButton。然而,没有任何反应进度条,即使耗时的操作(在这种情况下下载),并需要几秒钟:如何设置ProgressBar以在每个计时器的滴答时间递增?

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事件处理程序正确触发,但代码从不跳转到事件处理程序。有任何想法吗?

+4

我看不到任何InitializeTimer()的调用 – 2012-07-13 18:41:32

+0

把断点'searchProgressBar.Incriment(1)'。您可以通过单击该行左侧的边距来完成此操作。一个红点会出现让你知道一个断点在那里。在调试器中运行该程序,查看断点是否被命中。 – 2012-07-13 18:43:31

+0

http://stackoverflow.com/a/11033200/763026 – 2012-07-14 14:31:48

回答

2

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

和2)System.Windows.Forms.Timer在UI线程上产生它的tick事件..这是你耗时操作的同一个线程。您需要偶尔对消息泵进行控制,以便进行处理。

+0

这两个都是问题所在。我更新了代码以包含对“BackgroundWorker”及其功能的调用。我打算接受你的答案,但是我应该编辑我的问题并*添加*可以工作的代码? – 2012-07-13 19:10:03

+0

在问题中添加工作代码可以让未来的搜索者更快地得到答案。你决定。 – 2012-07-13 20:56:31

3

你在这里做的是有点混乱。假设你实际上正在初始化计时器 - 我认为这是发生了什么...

​​类完全运行在窗体的消息循环中,因此它不能在该函数在该线程上运行时触发。因此,虽然你的计时器Start()Click()函数在与定时器相同的线程上运行,所以定时器在该函数返回之前不会触发。但是,在该函数返回之前您再次返回定时器Stop()

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

如果你为此产生了一个不同的线程,不要忘记在主UI线程上调用任何UI更改或对UI元素的更改!

1

调试这个代码只是向我表明了SearchButton_Click事件处理火灾正确,但代码永远不会跳转到searchProgressTimer_Tick事件处理程序。

请尝试移动IntializeTimer()程序到你的窗体的构造,因为它看起来像你从来没有布线了定时器的Tick事件:

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

这是因为你的图形用户界面更新是在同一个线程中发生数据库操作。数据库操作应在不同的线程中完成,并调用GUI线程通知更新。看看这个,因为它解释得很好。

http://www.dotnetperls.com/progressbar

+1

如果你在同一个线程中完成你的时间密集型工作,你的进度条永远不会正常工作。后台工作人员是为了这样的任务而制作的。 – 2012-07-13 18:49:50

相关问题