Arg*_*gon 1 c# asynchronous while-loop
如何打破异步方法内部的while循环。请参考下面的代码
我尝试了很多方法,但没有一个对我有用
async void TotalTimer(string time)
{
while (true)
{
TimeSpan timesp = DateTime.Now - DateTime.Parse(time);
TotalTime = timesp.Hours + " : " + timesp.Minutes + " : " + timesp.Seconds;
await Task.Delay(1000);
if (string.IsNullOrEmpty(time))
{
break;
}
}
}
Run Code Online (Sandbox Code Playgroud)
我需要停止并退出循环
更新的代码:
async Task TotalTimer(CancellationToken token)
{
var intime = await App.Database.GetRecentIn();
InTime = DateTime.Parse(intime.datetime).ToString("hh:mm tt");
while (!token.IsCancellationRequested)
{
TimeSpan timesp = DateTime.Now - DateTime.Parse(intime.datetime);
TotalTime = timesp.Hours + " : " + timesp.Minutes + " : " + timesp.Seconds;
Console.WriteLine(TotalTime); // to see it's working
await Task.Delay(1000);
if (token.IsCancellationRequested)
{
break;
}
}
}
void StatCounting()
{
var cts = new CancellationTokenSource();
_= TotalTimer(cts.Token);
}
void StopCounting()
{
var cts = new CancellationTokenSource();
cts.Cancel();
_= TotalTimer(cts.Token);
_=Finalize();
}
Run Code Online (Sandbox Code Playgroud)
CancellationToken像这样使用:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApp
{
class Program
{
private string TotalTime;
static void Main(string[] args)
{
new Program().Run();
}
private void Run()
{
var cts = new CancellationTokenSource();
TotalTimer("00:00:00", cts.Token);
Console.ReadLine(); // waits for you to press 'Enter' to stop TotalTimer execution.
cts.Cancel();
Console.WriteLine("Press 'Enter' to exit the program.");
Console.ReadLine(); // waits for you to press 'Enter' to exit the program. See, TotalTimer stopped.
}
// your original method modified
async void TotalTimer(string time, CancellationToken token)
{
while (!token.IsCancellationRequested)
{
TimeSpan timesp = DateTime.Now - DateTime.Parse(time);
TotalTime = timesp.Hours + " : " + timesp.Minutes + " : " + timesp.Seconds;
Console.WriteLine(TotalTime); // to see it's working
await Task.Delay(5000, token);
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
更新资料
@Henk Holterman,根据编辑历史,if (string.IsNullOrEmpty(time))似乎是从外面打破循环的尝试。但这毫无意义,原因有二:
time为null或为空DateTime.Parse(time)(在原始帖子中),则在检查之前抛出将令牌添加到Task.Delay是一个好点。这样做可以节省资源,尽管对可观察的行为没有影响。
更新2
@Argon,代码独立于wpf,winforms,console或什么的。参见wpf下面的最小示例。我检查了它的工作情况。如果某些操作不适用于您的具体代码,则您可能向我们隐藏了一些细节。
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
namespace WpfApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private string TotalTime;
private CancellationTokenSource cts;
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
cts = new CancellationTokenSource();
TotalTimer("00:00:00", cts.Token);
}
async void TotalTimer(string time, CancellationToken token)
{
try
{
while (!token.IsCancellationRequested)
{
TimeSpan timesp = DateTime.Now - DateTime.Parse(time);
TotalTime = timesp.Hours + " : " + timesp.Minutes + " : " + timesp.Seconds;
label1.Content = TotalTime;
await Task.Delay(5000, token);
}
}
catch(OperationCanceledException)
{
label1.Content = "Canceled";
}
}
private void Button_Click(object sender, RoutedEventArgs e)
{
cts.Cancel();
}
}
}
Run Code Online (Sandbox Code Playgroud)