我正在尝试使用Timer在代码中产生延迟。间隔是10毫秒,我的经验函数是timer1_Tick
。计时器启动,这些是我的功能:
private void timer1_Tick(object sender, EventArgs e)
{
if (delay_ms != 0)
{
delay_ms--;
}
}
void Timer_Delay(uint delay)
{
delay_ms = delay;
while (delay_ms != 0) ;
}
我的timer1_Tick
工作正常(已测试),但在Timer_Delay
函数中,代码会在while (delay_ms != 0) ;
行中挂起。它应该在Timer_Delay(100)
右边1秒后通过这条线?
以下是使用Timer延迟而不是Thread.sleep
if (ROTOR_TIME_CONSTANT.BackColor.Equals(Color.Thistle))
{
do
{
serialPort.Write("vA" + ROTOR_TIME_CONSTANT.Value + "*");
//System.Threading.Thread.Sleep(20);
Timer_Delay(100);
} while (ROTOR_TIME_CONSTANT.BackColor.Equals(Color.Thistle));
答案 0 :(得分:2)
请改用Thread.Sleep(delayInMilliseconds)
。查看文档here
如果您想使用计时器,可以使用EventWaitHandle:
EventWaitHandle ewh;
uint delay_ms;
private void timer1_Tick(object sender, EventArgs e)
{
if (delay_ms != 0)
{
delay_ms--;
if(delay_ms == 0)
{
ewh.Set();
}
}
}
void Timer_Delay(uint delay)
{
ewh = new EventWaitHandle(false, EventResetMode.ManualReset);
delay_ms = delay;
ewh.WaitOne();
}
这在使用System.Windows.Forms.Timer的WinForms环境中不起作用,因为它在UI的同一个线程上运行。因此,如果您阻止UI的线程,您的计时器将永远不会打勾。如果您仍想使用计时器,则可以使用System.Timers.Timer,这更准确并且在单独的线程上运行,但这样您就会阻止UI,直到延迟过去,因为您正在阻止其线程。
如果您需要等待,您可以先创建一个单独的线程并在那里运行您的进程,因此如果您暂停该线程,UI将保持响应。
答案 1 :(得分:1)
在UI线程上引发了计时器的tick事件。您正在使用无限循环阻止UI线程:
while (delay_ms != 0)
所以Timer永远不会打勾。
答案 2 :(得分:0)
如果您想暂时停止计时器并重新启动计时器,可以考虑以下事项:
async Task Timer_Delay(uint delay)
{
timer.Stop();
await System.Threading.Tasks.Task.Delay(delay);
timer.Start();
}
您可以使用以下方法从异步方法调用此方法:
await Timer_Delay(5000);
修改强>
从声明为await Timer_Delay(5000);
的方法中使用async
将执行您指定的许多毫秒(在本例中为5000)但不会与Thread.Sleep
具有相同的效果阻止主线程。
这将在从调用的方法中暂停执行,直到计时器再次启动(如上面的Timer_Delay
方法所示。
答案 3 :(得分:0)
如果我理解你,你可以使用Timer类。
public Timer(TimerCallback callback, object state, int dueTime, int period);
例如:
class Program
{
static void Main(string[] args)
{
//Where Hello is a callback, null will be send as an argument to Hello method
//2000 is a delay in milliseconds, Timeout.Infinite is periodic of calling a method
Timer timer = new Timer(Hello, null, 2000,Timeout.Infinite);
Console.ReadKey();
}
static void Hello(Object o)
{
Console.WriteLine("Hello World");
}
}
有关详细信息,请参阅此主题:https://msdn.microsoft.com/ru-ru/library/system.threading.timer%28v=vs.110%29.aspx
答案 4 :(得分:-1)
Kordik得到了相关的帖子。你在UI中有一个线程,当它正在流失时,会破坏你的计时器滴答。拿这个简单的代码:
int x = 0;
private void timer1_Tick(object sender, EventArgs e)
{
x++;
textBox1.Text = x.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
DateTime start = DateTime.Now;
while ((DateTime.Now - start).TotalSeconds < 4)
{
System.Threading.Thread.Sleep(10);
}
}
...当您点击该按钮时,计时器将停止熄灭四秒钟(并且它也不会追溯性地触发事件。)
通过安排异步等待和类似的东西,而不是解决这个问题?让GUI启动一个单独的线程进行处理。无论用户交互或系统事件是什么,或者什么启动这个BackColor检查的整个大功能?让它在一个单独的线程中启动,你绕过了这个问题(以及各种其他问题,如无响应。)
...或者失败,在主循环中包含各种Application.DoEvents()。这将让UI线程仍然继续处理tick事件。 (在我的示例中,在System.Threading.Thread.Sleep(10)旁边添加Application.DoEvents()将使计时器继续工作。