【问题标题】:How to abort previous execution of an event when it's called again?再次调用事件时如何中止先前的事件执行?
【发布时间】:2020-05-22 06:20:55
【问题描述】:

我知道这可能是我应该能够很容易地用谷歌搜索的一个,但现在不确定要搜索什么......

基本上,我有一个引发的事件,当它仍在执行时,它可能会再次引发。如果发生这种情况,我想立即终止之前的任何执行。

在这种特定情况下,我说的是 DataGridView 的 SelectionChanged 事件。在我向这个项目介绍异步编程之前,没有任何问题。但是现在我发现当该方法等待异步调用的结果时,它可能会再次被引发。并且新调用可能会在原始调用之前完成,从而导致 UI 状态不一致。

【问题讨论】:

  • 可能会在 SelectionChanged 引发时将任务放入队列中?
  • 异步操作是否接受CancellationToken
  • 请分享你的代码
  • SelectionChanged 触发的程序正在执行时,用户是否不应该选择其他任何东西?如果不是,那么它并不意味着是异步的。这些选择变化是否意味着网格其他值的变化?还是其他控件?数据本身?如果是这样,它可能并不意味着是异步的。用户是否可以触发选择更改和/或相同元素的值更改或受/将受SelectionChange 触发的异步过程影响的元素?如果是这样,则不是异步的。如果表单关闭怎么办?这会对 async proc 的操作产生影响吗?
  • 如果该过程由选择更改触发,则意味着更改其他地方(不影响当前用户输入),并且这些更改也意味着它们的顺序性质/结果集,然后使用顺序代理(队列)处理它们。可以中断这些程序而不会造成伤害吗?然后使用 CancellationTokenSource 发出信号让任务顺利退出,因为知道运行它们的 UI 线程中的元素可能无法再访问了。

标签: c# winforms events async-await


【解决方案1】:

这样的事情怎么样:

    private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
    public async void OnMainThread()
    {
        cancellationTokenSource.Cancel();
        var newCts = new CancellationTokenSource();
        cancellationTokenSource = newCts;
        try
        {
            var result = await AsyncOp(newCts.Token);
            if (!newCts.IsCancellationRequested)
            {
                // Update UI
            }
        }
        catch (OperationCanceledException)
        {
            // Ignore
        }
    }

    public async Task<int> AsyncOp(CancellationToken cancel)
    {
        // Do the async work
        return 0;
    }

【讨论】:

  • 非常好!你可以直接调用newCts.Token.ThrowIfCancellationRequested(); 而不是if (!newCts.IsCancellationRequested),这样会更简洁一些。
  • 这行得通……虽然很奇怪,catch 块似乎从未被击中。让我想知道这种变化是否对其产生了如此轻微的影响,足以使其以正确的顺序自然排序。
  • 另外,对于任何未来阅读本文的人来说,认为 AsyncOp 必须采用取消令牌才能工作,我实际上并没有更新我的 AsyncOp 以采用取消令牌。我的调用了一个 Web 服务,它无论如何都会完成运行,但这没什么大不了的。主要的事情就是忽略结果。
猜你喜欢
  • 2012-10-19
  • 1970-01-01
  • 1970-01-01
  • 2020-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-26
相关资源
最近更新 更多