替代Thread.Sleep在Windows窗体中除了Timer

use*_*819 0 c# multithreading timer winforms

我在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);
 }
Run Code Online (Sandbox Code Playgroud)

使用上面的代码会导致形式无响应.使用Timer会产生嵌套计时器.而且在我的情况下并不成功.请告诉我Windows窗体的另一种选择.想要命令之间的特定暂停.

Ser*_*rvy 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您无法访问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;
}
Run Code Online (Sandbox Code Playgroud)

使用它我们现在可以写:

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();
Run Code Online (Sandbox Code Playgroud)

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

如果我们回到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();
}
Run Code Online (Sandbox Code Playgroud)

然后我们可以嵌入调用:

ExecuteIn(1000, () =>
{
    GotoMeasurementMode(3000);
    ExecuteIn(3000, () =>
    {
        query(device.Text);
        ExecuteIn(7000, () => StopMeasurement());
    });
});
Run Code Online (Sandbox Code Playgroud)

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

  • 好吧,如果它确实如此,我会再次爱上C#. (3认同)
  • @StephenCleary嗯,对我而言,编写/复制四行方法比引用另一个程序集更容易*.这可能是一个更好的主意,特别是如果你使用它很多,因为该实现处理一些边缘情况,但事实并非如此.如果您正在利用库中的其他功能,那么它可能会更容易. (2认同)