0

我在 Windows 窗体 C# 中使用 Thread.Sleep。使用它会导致不响应表单。使用 Timer 也不符合我的目的。

示例代码:

if(......)    // There are many if with difrent components and many Thread.sleep
{
      button.visible=true;
      Thread.sleep(1000);
      GotoMeasurementMode(3000);
      Thread.sleep(3000);
      query(device.Text);
      Thread.sleep(7000);
      StopMeasurement();
      Thread.sleep(4000);
 }

使用上述代码会导致表单无响应。使用 Timer 会导致嵌套计时器。在我的情况下是不可行的。请告诉我Windows形式的替代方案。想要命令之间的特定停顿。

4

3 回答 3

13

最简单的选择是使用这个模型:

public async void button1_Click(object sender, EventArgs args)
{
    if(condition)
    {
        button.visible=true;
        await Task.Delay(1000);
        GotoMeasurementMode(3000);
        await Task.Delay(3000);
        query(device.Text);
        await Task.Delay(7000);
        StopMeasurement();
        await Task.Delay(4000);
    }
}

如果您无权访问 C# 5.0,则可以在 4.0 中执行此操作。您需要从自己的Delay方法开始,因为 .NET 4.0 中不存在这种方法:

public static Task Delay(int milliseconds)
{
    var tcs = new TaskCompletionSource<bool>();
    var timer = new System.Threading.Timer(o => tcs.SetResult(false));
    timer.Change(milliseconds, -1);
    return tcs.Task;
}

使用它,我们现在可以编写:

Delay(1000)
    .ContinueWith(t => GotoMeasurementMode(3000), TaskScheduler.FromCurrentSynchronizationContext())
    .ContinueWith(t => Delay(3000)).Unwrap()
    .ContinueWith(t => query(device.Text), TaskScheduler.FromCurrentSynchronizationContext())
    .ContinueWith(t => Delay(7000)).Unwrap()
    .ContinueWith(t => StopMeasurement(), TaskScheduler.FromCurrentSynchronizationContext())
    .ContinueWith(t => Delay(4000)).Unwrap();

这与第一个片段将被编译成的代码非常相似,但显然第一个更漂亮,所以你应该尽可能使用它。

如果我们回到 C# 3.0,那么我们将无法访问Task,这意味着我们又回到了使用计时器和回调。我们将从这个简单的辅助方法开始为我们处理管理任务:

public static void ExecuteIn(int milliseconds, Action action)
{
    var timer = new System.Windows.Forms.Timer();
    timer.Tick += (s, e) => { action(); timer.Stop(); };
    timer.Interval = milliseconds;
    timer.Start();
}

然后我们可以嵌套调用这个:

ExecuteIn(1000, () =>
{
    GotoMeasurementMode(3000);
    ExecuteIn(3000, () =>
    {
        query(device.Text);
        ExecuteIn(7000, () => StopMeasurement());
    });
});

虽然可以在 C# 3.0 中重新创建 a Task(它不利用任何 4.0 语言功能)并且现有的库可以做到这一点,但这会涉及更多。

于 2013-05-29T16:39:43.737 回答
1

将上面的代码放在后台线程中,这样就不会阻塞 UI 线程。假设您在等待之间的方法需要 UI 访问,他们可以使用 Control.BeginInvoke 在 UI 线程上进行更新。

于 2013-05-29T16:41:55.190 回答
0

你应该考虑一个BackgroundWorker

目前只有 .NET framework 4.5 支持 async-await 机制。

如果您正在寻找向后兼容的解决方案,您应该查看CodeProject上的此链接。

后台工作人员将在单独的线程上下文中异步执行您的任务,以实现长时间运行的进程,保持您的 UI 响应能力,

希望能帮助到你

于 2013-05-29T16:44:01.200 回答