UWP:如何确保异步事件按顺序处理

UWP: How to make sure async events are processed sequentially

我需要一个事件处理程序来在我的 UWP 项目中拖动一个元素来执行等待的操作。

因此我需要将我的事件处理程序标记为异步:

myElement.PointerMoved += OnPointerMoved;

public async void OnPointerMoved(object sender, PointerRoutedEventArgs e)
{
 await MyOperationAsync(); 
}

因此,我发现即使之前的执行未完成,UWP 框架也会调用 OnPointerMoved(这是可以预见的,因为您不能等待 async void 方法...)。

我正在寻找一种解决方案,以确保我的事件处理程序中的代码被顺序调用(即 OnPointerMoved 的下一次执行应该在前一个实际完成之后发生)。

有人对此有优雅的解决方案吗?

这实际上是常见 producer/consumer problem 的一个实例,网络上有许多解决方案。

但是在您的情况下,由于事件始终在 UI 线程上触发,因此情况要容易一些。因此,您可以创建一个将操作排队的中间方法,而不是立即执行 运行 操作:

private bool _isProcessing = false;
private readonly Queue<PointerPoint> _operationQueue = new Queue<PointerPoint>();

private async Task EnqueueOperationAsync(PointerPoint point)
{
    //using the pointer point as argument of my operation in this example
    _operationQueue.Enqueue(point); 
    if (!_isProcessing)
    {
        _isProcessing = true;
        while (_operationQueue.Count != 0)
        {
            var argument = _operationQueue.Dequeue();
            await MyOperationAsync(argument);
        }
        _isProcessing = false;
    }
}

private async void UIElement_OnPointerMoved(object sender, PointerRoutedEventArgs e)
{
    await EnqueueOperationAsync(e.GetCurrentPoint(this));
}

如果您确定 EnqueueOperationAsync 仅从 UI 线程调用(如果它是由 OnPointerMoved 触发的情况),这应该完全按照您的要求工作谢谢事实上,只有一个 UI 线程,并且由于 await 自动返回到 UI 线程,EnqueueOperationAsync 方法唯一可以离开 [=41] 的地方=] 线程正在 MyOperationAsync 执行期间,在这种情况下 _isProcessing 必须是 true,因此新到达的操作将仅入队,并在 MyOperationAsync 完成后处理并且在 UI 线程上执行 returns。一旦没有更多要处理的内容,while 终止,_operationQueue 为空并且 _isProcessing 设置为 false - 准备好迎接另一个活动的到来。

我认为这个解决方案在简单情况下就足够了,并且实际上应该是安全的,除非有人从非 UI 线程调用 EnqueueOperationAsync

您甚至可以在方法的开头检查这一点:

if (CoreWindow.GetForCurrentThread().Dispatcher.HasThreadAccess)
   throw new InvalidOperationException(
         "This method must be called from the UI thread");

注意:尽管从我的测试来看逻辑似乎是可靠的,但我还是宁愿与其他人核实一下:-)