C# 线程的替代品。在windows窗体中睡眠,不使用计时器
我正在使用线程。在windows窗体C#中睡眠。使用它会导致表单不响应。 使用定时器也不符合我的目的 示例代码:C# 线程的替代品。在windows窗体中睡眠,不使用计时器,c#,multithreading,winforms,timer,C#,Multithreading,Winforms,Timer,我正在使用线程。在windows窗体C#中睡眠。使用它会导致表单不响应。 使用定时器也不符合我的目的 示例代码: if(......) // There are many if with difrent components and many Thread.sleep { button.visible=true; Thread.sleep(1000); GotoMeasurementMode(3000); Thread.sleep(3000)
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);
}
使用上述代码会导致形式上的不负责任。使用计时器将导致嵌套计时器。这对我来说是不必要的。
请告诉我windows窗体中的其他选项。需要命令之间的特定暂停。最简单的选择是使用此模型:
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;
}
这与第一个代码段将被编译成的代码非常相似,但显然第一个代码段要漂亮得多,所以如果可能的话,您应该使用它
如果我们回到C#3.0,那么我们将无法访问任务
,这意味着我们将重新使用计时器和回调。我们将从这个简单的助手方法开始,为我们管理任务:
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中重新创建一个
任务
(它不利用任何4.0语言功能),而且现有的库也可以这样做,但这将更加复杂。将上述代码放在后台线程中,这样就不会阻塞UI线程。假设你的方法在等待之间需要UI访问,他们可以使用控制。开始调用在UI线程上进行更新。 你应该考虑一个. 目前只有.NET framework 4.5支持异步等待机制
如果您正在寻找向后兼容的解决方案,您应该在上查看此链接 后台工作程序将在一个单独的线程上下文中异步执行您的任务,以便长时间运行进程,保持您的UI响应能力希望它对多线程有帮助,winforms程序的UI线程上没有任何其他选项调用Thread.Sleep()。用户界面进入睡眠状态。改用定时器。我个人认为永远不要调用
Thread.Sleep()
,句号。它的存在不可避免地带来了比它解决的问题更多的问题。但这是另一个时间的问题。@cHao我认为在某些情况下调用线程是有效的。Sleep(0)
。@cHao-请建议在从多个线程调用、从多个位置调用和调用堆栈中的几个级别调用的函数中延迟五秒钟。这将是理想的选择,但只在.NET4.5上可用。好吧,如果那样做的话,我会再次爱上C#的。@JohnField在那里还添加了一个C#4.0解决方案。如果这很重要的话,也可以很容易地修改它,使其在3.0或2.0中工作,但这需要更多的工作。C#4.0有一个更简单的解决方案:添加NuGet包Microsoft.Bcl.Async
,然后使用TaskEx.Delay
而不是Task.Delay
@StephenCleary,对我来说,编写/复制一个四行方法比引用一个附加程序集更容易。不过,这可能是一个更好的主意,特别是如果您经常使用它,因为该实现可以处理一些边缘情况,但实际上并没有。如果你正在利用库中的其他功能,那么这可能会更容易。你的意思是说,将包含所有If语句的整个代码放在一个线程中?但这会在一段较长的时间内阻塞一个线程,与异步执行代码相比,这是不必要的浪费资源。是-在单独的线程中运行所有内容(使用您选择的任务、BackgroundWorker或线程启动)。休眠和非基于UI的代码将异步工作。任何访问UI组件的操作都会引发异常,所以请将该部分包装在BeginInvoke中。请参阅Servy-休眠线程阻塞该线程,但它不会旋转CPU,这类似于使用SpinWait,我不提倡使用它。@Servy-是的。这将是数千个,因此与许多应用程序无关。你不需要使用.NET4.5来使用异步编程,它只是让它更容易。
ExecuteIn(1000, () =>
{
GotoMeasurementMode(3000);
ExecuteIn(3000, () =>
{
query(device.Text);
ExecuteIn(7000, () => StopMeasurement());
});
});