[英]How to pause inside a loop without using Thread.Sleep?
使用Thread.Sleep
我设法在循环内暂停,但它的缺点是在暂停持续时冻结我的程序。 我的程序的目的是在单击一个按钮时启动一个循环,并在单击另一个按钮时停止这个循环。 这是我写的代码:
private void startRPLoop_Click(object sender, EventArgs e)
{
timer1.Interval = 1000;
timer1.Enabled = true;
}
private void stopRPLoop_Click(object sender, EventArgs e)
{
timer1.Interval = 1000;
timer1.Enabled = false;
}
private void timer1_Tick(object sender, EventArgs e)
{
if (timer1.Enabled == true)
{
GlobalRPValue = 500;
WantedLevel = 1;
Thread.Sleep(1000);
WantedLevel = 0;
Thread.Sleep(1000);
}
else
{
GlobalRPValue = 1;
WantedLevel = 0;
}
}
我想创建一个Task
,这样我就可以使用await Task.Delay();
这将允许我启动循环并暂停我的程序而不会因为Thread.Sleep
而被暂停,但我不知道该怎么做。
我希望我足够精确,因为我是 C# 新手,感谢您的帮助:)
您的问题是如何在不使用 Thread.Sleep 的情况下在循环内暂停? . 您发布了一些使用System.Windows.Forms.Timer
的示例代码,但是当我使用Timer
解决它时,它需要更复杂的代码。 这个答案提出了一个更简单的解决方案,(基于我们的对话)在不使用Timer
的情况下做你想做的事。 单击按钮时它会运行一个循环,并每秒一次在 0 和 1 之间切换WantedLevel
,而不会冻结您的 UI。
“按钮”实际上是一个带有Appearance
= Button
的复选框。 单击它会切换选中状态,并且当切换为打开时,它会启动一个循环。 首先, onTick
方法在返回前将 WantedLevel 设置WantedLevel to 1
持续 1 秒。 然后它将在重复该过程之前await
额外的 1 秒延迟。
CancellationTokenSource _cts = null;
private async void checkBoxLoop_CheckedChanged(object sender, EventArgs e)
{
if(checkBoxLoop.Checked)
{
labelGlobalRPValue.Text = "GlobalRPValue=500";
textBoxConsole.Text = $"{DateTime.Now.ToString(@"mm:ss")}: Start clicked{Environment.NewLine}";
textBoxConsole.AppendText($"{DateTime.Now.ToString(@"mm:ss")}: {labelGlobalRPValue.Text} {Environment.NewLine}");
_cts = new CancellationTokenSource();
while (checkBoxLoop.Checked)
{
try {
await onTick(_cts.Token);
await Task.Delay(1000, _cts.Token);
}
catch(TaskCanceledException)
{
break;
}
}
ResetDefaults();
}
else
{
textBoxConsole.AppendText($"{DateTime.Now.ToString(@"mm:ss")}: Stop clicked{Environment.NewLine}");
_cts?.Cancel();
}
}
onTick
处理程序被标记为async
,它允许等待Task.Delay
。 除此之外,它非常简单,并尝试遵循您发布的处理程序的本质。
private async Task onTick(CancellationToken token)
{
labelWantedLevel.Text = "WantedLevel=1";
textBoxConsole.AppendText($"{DateTime.Now.ToString(@"mm:ss")}: {labelWantedLevel.Text} {Environment.NewLine}");
await Task.Delay(1000, token);
labelWantedLevel.Text = "WantedLevel=0";
textBoxConsole.AppendText($"{DateTime.Now.ToString(@"mm:ss")}: {labelWantedLevel.Text} {Environment.NewLine}");
}
当复选框状态关闭时,它会使用CancellationTokenSource
取消当前的Task.Delay
,这会导致循环退出。 ResetDefaults()
方法来恢复WantedLevel
和GlobalRPValue
的默认值。
private void ResetDefaults()
{
labelGlobalRPValue.Text = "GlobalRPValue=1";
labelWantedLevel.Text = "WantedLevel=0";
textBoxConsole.AppendText($"{DateTime.Now.ToString(@"mm:ss")}: Cancelled (reset defaults) {Environment.NewLine}");
textBoxConsole.AppendText($"{labelGlobalRPValue.Text} {Environment.NewLine}");
textBoxConsole.AppendText($"{labelWantedLevel.Text} {Environment.NewLine}");
}
编辑以符合原始帖子的评论
手柄按钮
private bool _checkBoxLoop_Checked = false;
private void startRPLoop_Click(object sender, EventArgs e)
{
_checkBoxLoop_Checked = true;
checkBoxLoop_CheckedChanged(sender, e);
}
private void stopRPLoop_Click(object sender, EventArgs e)
{
_checkBoxLoop_Checked = false;
checkBoxLoop_CheckedChanged(sender, e);
}
启用/禁用按钮以确保操作安全
private async void checkBoxLoop_CheckedChanged(object sender, EventArgs e)
{
stopRPLoop.Enabled = _checkBoxLoop_Checked; // Added
startRPLoop.Enabled = !stopRPLoop.Enabled; // Added
if (_checkBoxLoop_Checked) // use member variable instead of checkbox state
{
labelGlobalRPValue.Text = "GlobalRPValue=500";
textBoxConsole.Text = $"{DateTime.Now.ToString(@"mm:ss")}: Start clicked{Environment.NewLine}";
textBoxConsole.AppendText($"{DateTime.Now.ToString(@"mm:ss")}: {labelGlobalRPValue.Text} {Environment.NewLine}");
_cts = new CancellationTokenSource();
while (_checkBoxLoop_Checked)
{
try {
await onTick(_cts.Token);
await Task.Delay(1000, _cts.Token);
}
catch(TaskCanceledException)
{
break;
}
}
ResetDefaults();
}
else
{
textBoxConsole.AppendText($"{DateTime.Now.ToString(@"mm:ss")}: Stop clicked{Environment.NewLine}");
_cts?.Cancel();
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.