假设我有一个标签和一个按钮。如果我单击按钮,标签将设置为某个文本,说“你好,世界!”,5秒后,它应该消失。够容易吧?我有以下实现:
private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Label = "hello, world!";
await Task.Delay(5_000);
Label = string.Empty;
}
现在让我说我有额外的要求,按钮应该在每次后续按钮点击时保持响应,现在标签文本应该在接下来的5秒内保持hello, world!
,即标签文本应保持5秒钟最后一次单击按钮。以前代码的问题是,如果我在2.5秒前点击了按钮并再次点击它,标签文本将在2.5秒后消失。我解决这个问题的想法是维护一个任务列表并添加延迟任务并在清除标签之前等待任务列表。这是实施:
private static readonly List<Task> TaskList = new List<Task>();
private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Label = "hello, world!";
TaskList.Add(Task.Delay(5_000));
await Task.WhenAll(TaskList);
if (TaskList.TrueForAll(t => t.IsCompleted))
{
TaskList.RemoveAll(t => t.IsCompleted);
Label = string.Empty;
}
}
据我所知,这个实现有效,但我对异步编程知之甚少,所以我不知道如何完全确定它的工作原理。
问题:
你会如何实现这个?有没有更好的方法来实现这个?我原本认为Task.WhenAll()
将负责等待所有任务完成,但似乎并非如此。我错了什么?
修改: 使用取消令牌实施:
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
Label = "hello, world!";
_cancellationTokenSource.Cancel();
_cancellationTokenSource = new CancellationTokenSource();
try
{
await Task.Delay(5_000, _cancellationTokenSource.Token);
Label = string.Empty;
} catch (TaskCanceledException) { }
}