wpf 当用户再次点击第一个正在进行的点击事件时,我如何取消它?

3yhwsihp  于 2022-12-14  发布在  其他
关注(0)|答案(4)|浏览(216)

我有一个按钮单击事件处理程序,其中我需要有3秒的延迟,使一些标志为真...所以它需要时间来完全执行功能,现在同时,如果用户再次单击按钮,那么这是使标志为真的第二次单击也...所以我想取消第一次单击事件,只要我收到另一个单击请求。
这是我的代码:

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

ghg1uchk1#

是的,我需要取消第一个方法的执行,并再次调用该方法...以便在第二次单击该方法后等待3秒
下面是一个简单的取消令牌示例:

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.**在本例中,只在Delay(...)方法中检查标记。如果需要在其他地方检查,请在此处插入对token.ThrowIfCancellationRequested();方法的调用。

iyr7buue

iyr7buue2#

您可以在单击按钮时更改变量,并在完成后将其更改回来,然后添加一个if语句来检查变量

rm5edbpk

rm5edbpk3#

就像xceing说的,你可以有一个变量来检查是否已经点击了,还没有完成这个过程。
以下是一个示例

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

你可以在进程完成后将变量设为false。2这样下次单击操作就可以正常工作了。

yruzcnhs

yruzcnhs4#

目前还不清楚您到底在做什么。一般的解决方案可以使用Task.Run执行可取消的任务,然后使用CancellationTokenSource取消它。重要的是将关联的CancellationToken传递给Task API(以及任何一般支持取消的异步API),以便启用完全的取消支持,例如取消Task.Delay

主窗口.xaml

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

主窗口.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);
  }
}

相关问题