我有一个简单的表单应该启动一个计时器,执行一个耗时的操作,并在该操作工作时以一定的间隔更新进度条。现在,耗时的操作绑定到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
事件处理程序。有什么想法吗?
答案 0 :(得分:3)
你在这里做的事情有点令人困惑。假设你实际上是在某处初始化计时器 - 我认为这就是正在发生的事情......
Forms.Timer
类完全在Form的Message Loop上运行,因此当该函数在该线程上运行时,它不会触发。因此,尽管您Start()
计时器,Click()
函数与计时器在同一个线程上运行,因此计时器在该函数返回之前无法触发。但是,在该函数再次返回Stop()
计时器之前。
也许您想查看Threading.Timer
。虽然 - 理想情况下你正在做的“工作” - 无论是数据库操作还是仅仅是一个愚蠢的嵌套for循环 - 应该在不同的线程上发生,这样GUI的消息循环仍然可以处理。
如果您为此生成了不同的线程,请不要忘记在主UI线程上调用任何UI更改或更改UI元素!
答案 1 :(得分:2)
这是因为您的GUI更新发生在与数据库操作相同的线程中。数据库操作应该在不同的线程中完成,并调用GUI线程通知它更新。看看这个,因为它解释得相当好。
答案 2 :(得分:2)
所以1)我没有在任何地方看到对InitializerTimer()的调用。
和2)System.Windows.Forms.Timer在UI线程上引发它的tick事件..你正在进行操作的同一个线程。您需要偶尔对消息泵进行控制,以便处理偶数。
答案 3 :(得分: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);
}