Home > database >  How can I cancel first ongoing click event when user click on it again?
How can I cancel first ongoing click event when user click on it again?

Time:12-06

I have a button click event handler in which I need to have 3 sec delay to make some flag true ..so it takes time to completely execute the function now meantime if the user click on the button again then this is making flag true for second click also...so I want to cancel the first click event as soon as I receive another click request.

This is my code :

 private async void ClickEventHandler(ClickEvent obj)
    {
        int indexOfSelectedItem = this.List.IndexOf(this.List.FirstOrDefault(x => Convert.ToDouble(x.Value) == obj.Value));

                if (indexOfSelectedItem > -1)
                {
                    for (int i = 0; i < indexOfSelectedItem; i  )
                    {
                        var item = this.List.ElementAtOrDefault(0);
                        this.List.RemoveAt(0);
                        this.List.Add(item);
                    }
                    this.IsScrollEnabled = false;
                    await Task.Delay(3000);
                    this.IsScrollEnabled = true;
                }
    }

CodePudding user response:

you could change a variable when the button gets clicked and change it back after it is done and then add an if statement checking the variable

CodePudding user response:

As like xceing said , you can have a variable to check if already clicked and yet to complete the process.

Here is a sample

//keep a variable to check already clicked and yet to complete the action
    bool clickEventInProgress = false;

    private async void ClickEventHandler(ClickEvent obj)
    {
        //check it before start processing click action
        if (!clickEventInProgress)
        {
            
            clickEventInProgress = true;
            
            int indexOfSelectedItem = this.List.IndexOf(this.List.FirstOrDefault(x => Convert.ToDouble(x.Value) == obj.Value));

            if (indexOfSelectedItem > -1)
            {
                for (int i = 0; i < indexOfSelectedItem; i  )
                {
                    var item = this.List.ElementAtOrDefault(0);
                    this.List.RemoveAt(0);
                    this.List.Add(item);
                }
                this.IsScrollEnabled = false;
                await Task.Delay(3000);
                this.IsScrollEnabled = true;
            }

            clickEventInProgress = false;
        }
    }

you can make the variable false, one the process completed . So that next click operation will work fine.

CodePudding user response:

It's not clear what exactly you are doing. A general solution could execute the cancellable task using Task.Run and then cancel it using a CancellationTokenSource. It's important to pass the associated CancellationToken to the Task API (and any asynchronous API that supports cancellation in general) too in order to enable full cancellation support e.g. cancellation of Task.Delay:

MainWindow.xaml

<Window>
  <Button Content="Go!"
          Click="OnClick" />
</Window>

MainWindow.xaml.cs

partial class MainWindow : Window
{
  private CancellationTokenSource CancellationTokenSource { get; set; }
  private SemaphoreSlim Semaphore { get; } = new SemaphoreSlim(1, 1);

  public MainWindow() => InitializeComponent();

  private async void OnClick(object sender, RoutedEventArgs e)
  {
    // If there is nothing to cancel, the reference is NULL
    this.CancellationTokenSource?.Cancel();

    // Wait for the previous operation to be cancelled.
    // If there is nothing to cancel the SemaphoreSlim has a free slot 
    // and the execution continues. 
    await this.Semaphore.WaitAsync();

    try
    {
      using (this.CancellationTokenSource = new CancellationTokenSource())
      {
        await RunCancellableOperationAsync(this.CancellationTokenSource.Token);
      }
    }
    catch (OperationCanceledException)
    {
      // Invalidate disposed object to make it unusable
      this.CancellationTokenSource = null;
    }
    finally // Cancellation completed
    {     
      this.Semaphore.Release();
    }
  }

  private async Task RunCancellableOperationAsync(CancellationToken cancellationToken)
  {
    // Execute blocking code concurrently to enable cancellation
    await Task.Run(() =>
    {
      for (int index = 0; index < 1000; index  )
      {
        // Abort the iteration if requested
        cancellationToken.ThrowIfCancellationRequested();

        // Simulate do something
        Thread.Sleep(5000);
      }
    }, cancellationToken);

    // Support cancellation of the delay
    await Task.Delay(TimeSpan.FromSeconds(3), cancellationToken);
  }
}

CodePudding user response:

Yes I need to cancel the execution of the first method and call the method again ..so that it will wait for 3 sec after clicking it on second time

A simple example with a cancellation token:

    private CancellationTokenSource tokenSource = new();
    private async void ClickEventHandler(ClickEvent obj)
    {
        // Since this method is called from the clicker,
        // it always starts on the main thread. Therefore,
        // there is no need for additional Thread-Safe.
        tokenSource.Cancel();
        tokenSource = new();
        CancellationToken token = tokenSource.Token;

        int indexOfSelectedItem = this.List.IndexOf(this.List.FirstOrDefault(x => Convert.ToDouble(x.Value) == obj.Value));

        if (indexOfSelectedItem > -1)
        {
            for (int i = 0; i < indexOfSelectedItem; i  )
            {
                var item = this.List.ElementAtOrDefault(0);
                this.List.RemoveAt(0);
                this.List.Add(item);
            }
            this.IsScrollEnabled = false;
            try
            {
                // If the cancellation is during the Delay, then an exception will be exited.
                await Task.Delay(3000, token); 
                this.IsScrollEnabled = true;
            }
            catch (Exception)
            {
                // Here, if necessary, actions in case the method is canceled.
            }
        }
    }

P.S. In the example, the token is checked only in the Delay(...) method. If you need to check somewhere else, then insert a call to the method token.ThrowIfCancellationRequested(); into this place.

  • Related