Xamarin.Forms 使用 PanGestureRecognizer - 在 UWP 上移出 Window 区域不会触发状态已取消或已完成

Xamarin.Forms using PanGestureRecognizer - move outside of Window area on UWP does not trigger Status Canceled or Completed

我的问题是关于 Xamarin.Forms 上的 PanGestureRecognizer,特别是关于 UWP。平移手势效果很好,菜单可以滑入和滑出,但是如果您将鼠标光标移出应用程序 window,它不会触发 GestureStatus.Canceled 或 GestureStatus.Completed。我已经简化了下面的代码,因为它并不重要。平移手势工作正常,菜单随平移滑入和滑出。问题是如果您将光标移出应用程序 window.

,它不会触发任何内容

代码如下:

panContainer 是一个简单的 ContentView。

var panGesture = new PanGestureRecognizer();
panGesture.PanUpdated += PanUpdated;
panContainer.GestureRecognizers.Add(panGesture);

private void PanUpdated(object sender,PanUpdatedEventArgs e) {
        switch(e.StatusType) {
            case GestureStatus.Started:
                break;
            case GestureStatus.Running:
                menuLayout.TranslationX = (float)e.TotalX;
                break;
            case GestureStatus.Completed:
            case GestureStatus.Canceled:  //I assumed this would be called!
                if(menuLayout.TranslationX < 100) {
                    Close();
                } else {
                    Open();
                }
                break;
        }
    }

提前致谢!

if you move the mouse cursor outside of the application window it does not trigger GestureStatus.Canceled, or GestureStatus.Completed. I've simplified the code below because it is not important. The pan gesture is working correctly and the menu is sliding in and out with the pan. The issue is it is not triggering anything if you move the cursor outside of the app window.

我已经测试了你的代码并重现了这个问题。我试图在源代码中找到问题的原因。我找到 the following code.

void OnPointerCanceled(object sender, PointerRoutedEventArgs e)
{
    uint id = e.Pointer.PointerId;
    if (_fingers.Contains(id))
        _fingers.Remove(id);

    PinchComplete(false);
    PanComplete(false);
}

void OnPointerExited(object sender, PointerRoutedEventArgs e)
{
    uint id = e.Pointer.PointerId;
    if (_fingers.Contains(id))
        _fingers.Remove(id);

    PinchComplete(true);
    PanComplete(true);
}

void OnPointerPressed(object sender, PointerRoutedEventArgs e)
{
    uint id = e.Pointer.PointerId;
    if (!_fingers.Contains(id))
        _fingers.Add(id);
}

void OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
    uint id = e.Pointer.PointerId;
    if (_fingers.Contains(id))
        _fingers.Remove(id);

    PinchComplete(true);
    PanComplete(true);
}

PanComplete方法会在你PointerExitedManipulationCompleted等时候调用,但是在指针退出的时候还没有调用。然后我尝试在 uwp 本机项目中测试 PointerExitedManipulationCompleted 事件。两者都正常工作。

<Border Width="200" Height="200"  Background="Red" PointerEntered="Border_PointerEntered" PointerExited="Border_PointerExited" ManipulationCompleted="Border_ManipulationCompleted"/>

所以,xamarin 可能存在一些问题。

基于先前评论的可行解决方案

//Shared part
public class PanOutsideWindowEffect : RoutingEffect
{
    public event EventHandler<PanUpdatedEventArgs> PanUpdated;

    public PanOutsideWindowEffect() : base($"{ResolutionGroupName.Organization}.{nameof(PanOutsideWindowEffect)}")
    {
    }

    public void SendPanCancel()
    {
        PanUpdated?.Invoke(this, new PanUpdatedEventArgs(GestureStatus.Canceled, 0));
    }
}

//UWP part
public class PanOutsideWindowEffect : PlatformEffect
{
    private FrameworkElement frameworkElement;
    private MobileApp.Effects.PanOutsideWindowEffect effect;

    protected override void OnAttached()
    {
        frameworkElement = Control == null ? Container : Control;
        effect = (MobileApp.Effects.PanOutsideWindowEffect)Element.Effects.First(e => e is MobileApp.Effects.PanOutsideWindowEffect);

        if (frameworkElement != null)
        {
            frameworkElement.PointerExited += OnPointerExited;
        }
    }

    protected override void OnDetached()
    {
        if (frameworkElement != null)
        {
            frameworkElement.PointerExited -= OnPointerExited;
        }
    }

    private void OnPointerExited(object sender, PointerRoutedEventArgs args)
    {
        effect?.SendPanCancel();
    }
}