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



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

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

myElement.PointerMoved += OnPointerMoved;
public async void OnPointerMoved(object sender, PointerRoutedEventArgs e)
{
await MyOperationAsync(); 
}

因此,我发现即使之前的执行没有完成,OnPointerMoved也会被UWP框架调用(这是可以预见的,因为你不能等待异步void方法…)

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

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

这实际上是一个常见的生产者/消费者问题的例子,该问题有许多解决方案在网上流传。

然而,在您的情况下,由于事件总是在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));
}

如果您确保仅从UI线程调用EnqueueOperationAsync(如果它是由OnPointerMoved触发的,则是这种情况),由于只有一个UI线程,并且由于await自动返回到UI线程,EnqueueOperationAsync方法唯一可以离开UI线程的地方是在MyOperationAsync执行期间,在这种情况下,_isProcessing必须是true,因此新到达的操作将仅排队,并且将在MyOperationAsync完成并且在UI线程上返回执行时进行处理。一旦没有更多要处理的内容,while终止,_operationQueue为空,_isProcessing设置为false-为即将到来的另一场活动做好准备。

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

你甚至可以在方法的开头检查一下:

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

注意:尽管我的测试逻辑似乎很可靠,但我宁愿与其他人一起检查:-)

相关内容

  • 没有找到相关文章

最新更新