繁体   English   中英

如何在不使用 Thread.Sleep 的情况下在循环内暂停?

[英]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()方法来恢复WantedLevelGlobalRPValue的默认值。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM