[英]How to pause inside a loop without using Thread.Sleep?
using Thread.Sleep
I manage to make a pause inside a loop but it has the disadvantage of freezing my program while the pause lasts.使用Thread.Sleep
我设法在循环内暂停,但它的缺点是在暂停持续时冻结我的程序。 The purpose of my program is to start a loop when a button is clicked and to stop this loop when another button is clicked.我的程序的目的是在单击一个按钮时启动一个循环,并在单击另一个按钮时停止这个循环。 Here is the code I wrote:这是我写的代码:
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;
}
}
I thought of creating a Task
so I could use await Task.Delay();
我想创建一个Task
,这样我就可以使用await Task.Delay();
which will allow me to start the loop and make pauses without my program being suspended because of Thread.Sleep
but I don't know how to go about it.这将允许我启动循环并暂停我的程序而不会因为Thread.Sleep
而被暂停,但我不知道该怎么做。
I hope I have been precise enough because I am new to C# and thank you for your help :)我希望我足够精确,因为我是 C# 新手,感谢您的帮助:)
Your question is How to pause inside a loop without using Thread.Sleep?您的问题是如何在不使用 Thread.Sleep 的情况下在循环内暂停? . . You posted some sample code that uses System.Windows.Forms.Timer
but when I worked it out using Timer
it required more complicated code.您发布了一些使用System.Windows.Forms.Timer
的示例代码,但是当我使用Timer
解决它时,它需要更复杂的代码。 This answer proposes a simpler solution that (based on our conversation) does what you want without using Timer
.这个答案提出了一个更简单的解决方案,(基于我们的对话)在不使用Timer
的情况下做你想做的事。 It runs a loop when the button is clicked and toggles the WantedLevel
between 0 and 1 once per second without freezing your UI.单击按钮时它会运行一个循环,并每秒一次在 0 和 1 之间切换WantedLevel
,而不会冻结您的 UI。
The "Button" is actually a checkbox with Appearance
= Button
. “按钮”实际上是一个带有Appearance
= Button
的复选框。 Clicking it will toggle the checked state and when toggled on, it starts a loop.单击它会切换选中状态,并且当切换为打开时,它会启动一个循环。 First, the onTick
method sets WantedLevel to 1
for a duration of 1 second before returning.首先, onTick
方法在返回前将 WantedLevel 设置WantedLevel to 1
持续 1 秒。 Then it will await
an additional 1-second delay before repeating the process.然后它将在重复该过程之前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();
}
}
The onTick
handler is marked async
which allows the Task.Delay
to be awaited. onTick
处理程序被标记为async
,它允许等待Task.Delay
。 Other than that it's quite simple and tries to follow the essence of the handler you posted.除此之外,它非常简单,并尝试遵循您发布的处理程序的本质。
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}");
}
When the checkbox state toggles off, it cancels the current Task.Delay
using the CancellationTokenSource
which causes the loop to exit.当复选框状态关闭时,它会使用CancellationTokenSource
取消当前的Task.Delay
,这会导致循环退出。 The ResetDefaults()
method is called to restore default values for WantedLevel
and GlobalRPValue
. 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}");
}
EDITS TO CONFORM TO ORIGINAL POST PER COMMENT编辑以符合原始帖子的评论
Handle Buttons手柄按钮
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);
}
Enable/Disable buttons for operational safety启用/禁用按钮以确保操作安全
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.