1

所以当我尝试按下“按钮 2”时,我预计会发生两件事 a)“dowsomething”应该在“now”类中做它的事情。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

4 回答 4

3

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

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

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

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

更精确的是 System.Threading 中的 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/

于 2013-03-15T16:47:00.157 回答
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";
    });
});
于 2013-03-15T16:42:05.603 回答
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

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

于 2013-03-15T16:45:31.357 回答
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方法中停止计时器(dsomething 完成后,控制返回到 RunWorkerCompleted 中的主线程) .

于 2013-03-15T17:03:44.300 回答