现在我已经实现了这样的计时器类。
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不会冻结。
希望有人可以帮助我。答案 0 :(得分:3)
如果你正在做大量的工作 - 甚至模拟它 - 你应该不在UI线程上做这件事。这就是你的UI线程冻结的原因。
您应该在后台线程上执行此操作,并使用Control.Invoke
/ BeginInvoke
或可能BackgroundWorker
将任何UI更新(例如更改进度条)封送回UI线程
目前还不清楚你的计时器在这里做了什么,但是当你找到如何将工作卸载到另一个线程时,然后描述你的代码是什么样的。
请注意,您可以使用System.Windows.Forms.Timer
轻松地与UI线程进行交互 - 但它仍然应该基于事件,而不是在UI线程中运行大量工作。因此,例如,您可以创建要执行的工作“队列”(基于列表框项目),设置计时器以每秒触发,并在每个计时器上执行工作 - 如果它很短 - 为该项目。在调用之间,UI线程可以自由更新。
请注意,C#5的异步功能意味着将能够像这样编写正常的顺序代码,但这还有一段距离。
答案 1 :(得分:0)
...
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();
...
答案 2 :(得分:0)
我认为这是你想要实现的目标。但是,我不确定当秒表开始和停止计时。您的示例似乎是多次启动手表并且只停止一次。
private int currItem;
private List<ElementControl> Elements = new List<ElementControl>();
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<ElementControl> Elements = new List<ElementControl>();
}
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!");
}
}