需要一个在列表框中的每个完成项目后更新的计时器

现在我已经实现了这样的计时器类。

static void DelaySec(string delayName) { switch (delayName) { case "Delay1": System.Threading.Thread.Sleep(1000); break; case "Delay2": System.Threading.Thread.Sleep(2000); break; case "Delay3": System.Threading.Thread.Sleep(3000); break; case "Delay4": System.Threading.Thread.Sleep(4000); break; case "Delay5": System.Threading.Thread.Sleep(5000); break; default: break; } } 

我想在列表框中的项目之间设置延迟而不是睡眠,这样我的UI就不会冻结。

希望有人可以帮助我。

如果你正在做大量工作 – 甚至模拟它 – 你应该在UI线程上做这件事。 这就是你的UI线程冻结的原因。

您应该在后台线程上执行此操作,并使用Control.Invoke / BeginInvoke或可能的BackgroundWorker将任何UI更新(例如更改进度条)封送回UI线程。

目前还不清楚你的计时器在这里应该做什么,但是当你研究出如何将工作卸载到另一个线程时, 然后描述你的代码是什么样的。

请注意,您可以使用System.Windows.Forms.Timer轻松地与UI线程进行交互 – 但它仍然应该基于事件,而不是在UI线程中运行大量工作。 因此,例如,您可以创建要执行的工作“队列”(基于列表框项目),设置计时器以每秒触发,并在每个计时器上执行工作 – 如果它很短 – 为该项目。 在调用之间,UI线程可以自由更新。

请注意,C#5的异步function意味着您能够像这样编写正常的顺序代码,但这还有一段距离。

  ... stopwatch.Start(); timerLabel.Visible = true; progressBar1.Maximum = SequenceListBox.Items.Count; progressBar1.Step = (progressBar1.Maximum / SequenceListBox.Items.Count); progressBar1.PerformStep(); foreach(ElementControl item in SequenceListBox.Items) { item.RunElement(); Application.DoEvents(); } stopwatch.Stop(); ... 

我想这就是你想要实现的目标。 但是,我不确定是否在秒表启动和停止计时。 您的示例似乎是多次启动手表并且只停止一次。

  private int currItem; private List Elements = new List(); private void StartButton_Click(object sender, EventArgs e) { if (SequenceListBox.Items.Count <= 0) { MessageBox.Show("Please select an Item"); return; } // Prevent starting again StartButton.Enabled = false; Elements.Clear(); foreach (ElementControl ele in SequenceListBox.Items) Elements.Add(ele); // Must start stopwatch before timer to prevent timer_Elapsed from closing a non-existent stopwatch stopwatch = Stopwatch.StartNew(); stopwatch.Start(); // Start timer System.Timers.Timer timer = new System.Timers.Timer(1000); timer.AutoReset = true; timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); timer.Start(); } public delegate void ReportProgressHandler(int value, string text); private void ReportProgress(int value, string text) { if (InvokeRequired) Invoke(new ReportProgressHandler(ReportProgress), value, text); else { if(value <= progressBar1.Maximum) progressBar1.Value = value; timerLabel.Text = text; } } private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { // If all item process, stop timer, stopwatch and re-enable button if (currItem >= Elements.Count) { timer.Stop(); stopwatch.Stop(); ReportProgress (curItem, stopwatch.Elapsed.TotalSeconds.ToString("0" + " sec")); stopwatch = null; MessageBox.Show("The Test is Finish"); //StartButton.Enabled = true; // Use the same approach as that used to report progress. } else { // Select item and run it ElementControl item = Elements[curItem]; item.RunElement(); currItem++; ReportProgress (curItem, "sometext")); } } 

这是另一种可能的方法:

  class Task { public List Elements = new List(); } private void buttonStart_Click(object sender, EventArgs e) { buttonStart.Enabled = false; Task task = new Task(); foreach (ElementControl ele in SequenceListBox.Items) task.Elements.Add(ele); progressBar1.Maximum = task.Elements.Count; backgroundWorker1.RunWorkerAsync(task); } public delegate void ReportProgressHandler(int value, string text); private void ReportProgress(int value, string text) { if (InvokeRequired) Invoke(new ReportProgressHandler(ReportProgress), value, text); else { if(value <= progressBar1.Maximum) progressBar1.Value = value; label1.Text = text; } } private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { Task task = e.Argument as Task; if (task != null) { int i = 0; foreach (ElementControl ele in task.Elements) { i++; ele.RunElement(); ReportProgress(i, "sometext + " + i.ToString()); System.Threading.Thread.Sleep(1000); } MessageBox.Show("Completed!"); } }