使用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# 新手,感謝您的幫助:)
uj5u.com熱心網友回復:
您的問題是如何在不使用 Thread.Sleep 的情況下在回圈內暫停?. 您發布了一些示例代碼,System.Windows.Forms.Timer但當我使用Timer它時需要更復雜的代碼。這個答案提出了一個更簡單的解決方案,(基于我們的對話)在不使用Timer. 單擊按鈕時它會運行一個回圈,WantedLevel并每秒在 0 和 1 之間切換一次,而不會凍結您的 UI。

“按鈕”實際上是一個帶有Appearance=的復選框Button。單擊它會切換選中狀態,并且當切換為打開時,它會啟動一個回圈。首先,該onTick方法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}");
}
當復選框狀態切換為關閉時,它會取消當前Task.Delay使用CancellationTokenSource導致回圈退出。呼叫該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();
}
}

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/496692.html
