简体   繁体   中英

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

My question is regarding the PanGestureRecognizer on Xamarin.Forms, specifically on UWP. The pan gesture works great and the menu slides in and out but 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.

Code below:

panContainer is a simple 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;
        }
    }

Thanks in advance!

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.

I have tested your code and reproduce the issue. I tried to find the cause of the problem in the source code. I found 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);
}

The PanComplete method will be invoked when you PointerExited , ManipulationCompleted etc. But it has not been invoked when the pointer exited. And then I tried to test PointerExited and ManipulationCompleted event in uwp native project. Both are working properly.

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

So,there may be some issues with xamarin.

Workable solution based on the previous comment

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM