'why Task delay not working in Window_KeyUp and Window_KeyDown methods?

I have three buttons. The timer should have started when I pressed any of the 3 optional buttons. For example. When I press the blueHeadTopBtn button, the timer starts. If I press one or both of the remaining 2 buttons in 1 second, it gives value to the label. in this case, if a button is pressed 2 times, the label should not be valued. When the window is loaded, it works when I click the buttons, but it does not work when I press the keyboard.

These buttons are working correctly but the codes in Window_KeyUp and Window_KeyDown methods are malfunctioning.

 private async void blueHeadTopBtn_Click(object sender, RoutedEventArgs e)
    {
        BlueHead();
        WinBluePoint();
        blueHeadTopBtn.IsEnabled = false;
        await Task.Delay(1000);
        blueHeadTopBtn.IsEnabled = true;
    }

    private async void blueHeadLeftBtn_Click(object sender, RoutedEventArgs e)
    {
        BlueHead();
        WinBluePoint();
        blueHeadLeftBtn.IsEnabled = false;
        await Task.Delay(1000);
        blueHeadLeftBtn.IsEnabled = true;
    }

    private async void blueHeadRightBtn_Click(object sender, RoutedEventArgs e)
    {
        BlueHead();
        WinBluePoint();
        blueHeadRightBtn.IsEnabled = false;
        await Task.Delay(1000);
        blueHeadRightBtn.IsEnabled = true;
    }

These codes are working incorrectly.

  private async void Window_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Q)
            {
                BlueHead();
                WinBluePoint();
                blueHeadTopBtn.IsEnabled = false;
                await Task.Delay(1000);
                blueHeadTopBtn.IsEnabled = true;
            }
            if (e.Key == Key.E)
            {
                BlueHead();
                WinBluePoint();
                blueHeadLeftBtn.IsEnabled = false;
                await Task.Delay(1000);
                blueHeadLeftBtn.IsEnabled = true;
            }
             if (e.Key == Key.R)
            {
                BlueHead();
                WinBluePoint();
                blueHeadRightBtn.IsEnabled = false;
                await Task.Delay(1000);
                blueHeadRightBtn.IsEnabled = true;
            }
        }

How can I solve this issue? Did I use TASK correctly?



Solution 1:[1]

I guess your code is wrong. From reviewing your mysterious code snippets, it appears like you want to disable a button for 1s after it was pressed. I assume you want to achieve the same with the keyboard input: ignore a particular key for 1s after it was pressed.
In your key up handlers you only disable the buttons. This of course has no effect on the keyboard input. You must disable the key event handling. To accomplish this, either unregister the event handler for the duration of the key lock or use a flag.

Instead of creating a flag for every key or button that should participate in the locking logic, this example uses a Dictionary which allows the implementation to scale without extra efforts. This also improves your code by eliminating the duplicate code that you had. Now, we can use a shared event handler for every button and a dedicated handler for keyboard input:

MainWindow.xaml.cs

partial class MainWindow : Window
{ 
  private Dictionary<object, DateTime> LockedInputSourceTable { get; }
  private TimeSpan UserInputLockDuration {get; }
  private DispatcherTimer InputLockTimer { get; }

  public MainWindow()
  {
    InitializeComponent();

    this.UserInputLockDuration = TimeSpan.FromSeconds(1);
    this.InputLockTimer = new DispatcherTimer(
      TimeSpan.FromMilliseconds(500), 
      DispatcherPriority.Input, 
      RemoveInputLock, 
      Application.Current.Dispatcher);
    this.LockedInputSourceTable = new Dictionary<object, DateTime>();
  }

  private void RemoveInputLock(object? sender, EventArgs e)
  {
    var currentTime = DateTime.Now;
    foreach (var entry in this.LockedInputSourceTable)
    {
      DateTime timeStamp = entry.Value;
      if (currentTime.Subtract(timeStamp) >= this.UserInputLockDuration)
      {
        object lockedObject = entry.Key;
        this.LockedInputSourceTable.Remove(lockedObject);
        if (lockedObject is UIElement uiElement)
        {
          uiElement.IsEnabled = true;
        }
      }
    }

    if (!this.LockedInputSourceTable.Any())
    {
      this.InputLockTimer.Stop();
    }
  }

  protected override void OnPreviewKeyUp(KeyEventArgs e)
  {
    var currentTime = DateTime.Now;
    base.OnPreviewKeyUp(e);

    if (this.LockedInputSourceTable.ContainsKey(e.Key))
    {
      return;
    }

    switch (e.Key)
    {
      case Key.Q:
      case Key.E:
      case Key.R:
        // Store timestamp and pressed key
        this.LockedInputSourceTable.Add(e.Key, currentTime);
        if (!this.InputLockTimer.IsEnabled)
        {
          this.InputLockTimer.Start();
        }

        BlueHead();
        WinBluePoint();
        break;
    }
  }

  private void DisableElement_OnClick(object sender, RoutedEventArgs e)
  {
    var currentTime = DateTime.Now;
    if (this.LockedInputSourceTable.ContainsKey(sender))
    {
      return;
    }

    this.LockedInputSourceTable.Add(sender, currentTime);
    if (!this.InputLockTimer.IsEnabled)
    {
      this.InputLockTimer.Start();
    }
    var uiElement = sender as UIElement;
    uiElement.IsEnabled = false;

    BlueHead();
    WinBluePoint();
  }
}

MainWindow.xaml

<Window>
  <StackPanel>
    <Button Click="DisableElement_OnClick" />
    <Button Click="DisableElement_OnClick" />
    <Button Click="DisableElement_OnClick" />
  </StackPanel>
</Window>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 BionicCode