c# Timer不会运行下来形成冻结

本文关键字:冻结 运行 Timer | 更新日期: 2023-09-27 18:04:21

所以当我尝试按下"button 2"时,我希望发生两件事a)"dowsomething"应该在"now"类中做它的事情。b)当它做某事时,我想让它计算某事需要多长时间。然而,因为"做某事"是程序饥饿Form1冻结,它不会运行定时器。我是c#的新手,所以我不知道如何在后台运行它。有什么新奇的想法吗?谢谢。

     int time = 0;
    private void button2_Click(object sender, EventArgs e)
    {
            timer1.Start();
            nowthen now = new nowthen();
            now.dosomething(withthis); //This task is program hungry and causes the form to freeze
            timer1.Stop();
            time = 0;  
    }
    private void timer1_Tick(object sender, EventArgs e)
    {
        time = time + 1;
        label2.Text = time.ToString();
        label2.Refresh();
    }

c# Timer不会运行下来形成冻结

在Windows窗体中,所有UI内容都运行在一个线程上。其中包括定时器——定时器是在后台用windows消息实现的。

你的问题实际上是两个问题:-

  1. 如何在c#/Windows窗体中计时操作?

如何计时取决于你所追求的精度。对于+/- 10ms范围内的精度,您可以使用Environment。TickCount -在操作之前存储它的值,然后在操作之后再次获取值,并减去存储的值-然后您有您的持续时间。

更精确的是System中的Stopwatch类。线程-参见http://www.dotnetperls.com/stopwatch
  1. 如何在后台运行任务?

要在后台运行操作,需要在不同的线程中运行。最简单、设计友好(但可能不是那么灵活)的方法是使用BackgroundWorker组件。这将使用工作线程为您执行操作。关于如何做到这一点,请参阅http://www.dotnetperls.com/backgroundworker。

更高级、更灵活的方法是创建自己的线程来完成这项工作。然而,这将产生一些重要的问题来考虑如何同步正在发生的事情——一旦你启动线程,你的方法调用完成(它是异步的),你需要有一个机制来通知你的UI代码进程已经完成。这个例子看起来和如何创建自己的线程一样好:http://www.daveoncsharp.com/2009/09/create-a-worker-thread-for-your-windows-form-in-csharp/

对于。net 4使用:

Task.Factory.StartNew((Action) delegate()
{
    // this code is now executing on a new thread.
    nowthen now = new nowthen();
    now.dosomething(withthis);
    // to update the UI from here, you must use Invoke to make the call on UI thread
    textBox1.Invoke((Action) delegate()
    {
          textBox1.Text = "This update occurs on the UI thread";
    });
});

如果你只是想计时,使用System.Diagnostics.Stopwatch。

Stopwatch sw = Stopwatch.StartNew();
nowThen = new nowThen();
no.dosomething(withthis);
sw.Stop();
// you can get the time it took from sw.Elapsed

但是,它不会用经过的时间更新标签。

我想我也会把这个扔进去,尽管它不像@paul的解决方案那样优雅。

timer1.Start();
var bw = new BackgroundWorker();
bw.DoWork += (s, e) => { now.dosomething((myArgumentType)e.Argument); };
bw.RunWorkerCompleted += (s, e) => { timer1.Stop(); };
bw.RunWorkerAsync(withthis);

这个启动你的定时器,创建一个新的BackgroundWorker线程,告诉它在DoWork方法中运行什么(dosomething在一个单独的线程中运行),然后在RunWorkerCompleted方法中停止定时器(在dosomething完成后,控制返回到RunWorkerCompleted的主线程)。