0
\$\begingroup\$

Let's say I have a label and a button. If I click the button, the label is set to some text, say "hello, world!", and after 5 seconds, it should disappear. Easy enough, right? I have the following implementation:

private async void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
  Label = "hello, world!";
  await Task.Delay(5_000);
  Label = string.Empty;
}

Now let's say I have the additional requirement that the button should remain responsive on each subsequent button click, and now the label text should remain hello, world! for the next 5 seconds i.e. the label text should remain for 5 seconds since the last time the button was clicked. The problem with the previous code is that if I had clicked the button 2.5 seconds ago and click it again now, the label text will disappear after 2.5 seconds. My idea to solve this was to maintain a list of tasks and add the delay task and await the task list before clearing the label. This is the implementation:

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;
  }
}

Implementation with a cancellation token:

private static 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) { }
}

As far as I know, these implementation works, but I don't know much about asynchronous programming so I don't know how to be absolutely sure it works.

Questions:
How would you implement this? Is there a better way to implement this? I originally figured that Task.WhenAll() would take care of waiting for all tasks to complete, but this does not seem to be the case. What am I getting wrong?

\$\endgroup\$
6
  • \$\begingroup\$ This looks very much like pseudocode. Can you post your real solution? \$\endgroup\$
    – t3chb0t
    Oct 30, 2017 at 8:09
  • \$\begingroup\$ Did you think about a timer instead of tasks? \$\endgroup\$
    – JanDotNet
    Oct 30, 2017 at 8:12
  • 1
    \$\begingroup\$ @t3chb0t It's not. This is the actual source code. \$\endgroup\$ Oct 30, 2017 at 10:42
  • \$\begingroup\$ I have rolled back the last edit. Please see What should I do when someone answers my question? \$\endgroup\$
    – t3chb0t
    Oct 30, 2017 at 13:51
  • \$\begingroup\$ You have Label = "hello, world!"; in your actual source? Why? \$\endgroup\$
    – Mast
    Oct 31, 2017 at 7:46

2 Answers 2

1
\$\begingroup\$

I would use a timer.

On callback, you set the content of your label to empty. You just have to restart the timer on every button click.

I think it simplifies a lot the code.

\$\endgroup\$
2
  • \$\begingroup\$ I added an implementation using your ideas at the bottom. Can you please comment? Thanks. \$\endgroup\$ Oct 30, 2017 at 13:49
  • \$\begingroup\$ @asfeynman: thanks for sharing your improved solution. If you want to discuss it, it is better to post it as new question (follow up). \$\endgroup\$
    – JanDotNet
    Oct 30, 2017 at 14:48
0
\$\begingroup\$

Here's an implementation suggested by @ogomrun using the timer class:

private Timer timer;
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
  Label = "hello, world!";
  if (timer == null)
  {
    timer = new Timer(state => Label = string.Empty, null, 5_000, Timeout.Infinite);
  }
  else
  {
    timer.Change(5_000, Timeout.Infinite);
  }
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.