C#Timer不会运行以形成冻结

时间:2013-03-15 16:37:44

标签: c# forms timer

所以当我尝试按下“按钮2”时,我希望发生两件事a)“dowsomething”假设在“现在”类中做它的事情。 b)虽然它做了一件事,我想要它计算一下这需要多长时间。然而,因为“dosomething”是程序饥饿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();
    }

4 个答案:

答案 0 :(得分:3)

在Windows窗体中,所有UI内容都在一个线程上运行。这包括计时器 - 计时器是在幕后用Windows消息实现的。

你的问题其实是两个问题: -

  1. 如何在C#/ Windows表单中计算操作?
  2. 如何计时取决于您所寻求的精确度。对于+/- 10ms范围内的准确度,您可以使用Environment.TickCount - 在操作之前存储它的值,然后在之后再次获取值,并减去存储的值 - 并且您有持续时间。

    更准确的是System.Threading中的Stopwatch类 - 请参阅http://www.dotnetperls.com/stopwatch

    1. 如何“在后台”运行任务?
    2. 要在后台运行您的操作,您需要在另一个线程中运行它。最简单,设计友好(但可能不是那么灵活)是使用BackgroundWorker组件。这包含使用工作线程为您执行操作。有关如何执行此操作的详细说明,请参阅http://www.dotnetperls.com/backgroundworker

      更高级,更灵活,就是创建自己的线程来完成工作。但是,这会产生一些重要的问题需要考虑如何同步正在进行的操作 - 一旦启动线程,您的方法调用结束(它是异步的)并且您需要有一个机制来通知您的UI代码该进程具有完了。这个例子与如何创建自己的线程一样好:http://www.daveoncsharp.com/2009/09/create-a-worker-thread-for-your-windows-form-in-csharp/

答案 1 :(得分:2)

对于.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";
    });
});

答案 2 :(得分:2)

如果您只想计算某事需要多长时间,请使用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

然而,这不会用经过的时间更新标签。

答案 3 :(得分:1)

我想我也会抛出它,虽然它不像@ 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中的主线程。