使用PanGestureRecognizer的Xamarin.Forms - 在UWP上移动到Window区域之外不会触发Status Cancelled或Completed

时间:2017-06-02 12:19:28

标签: c# uwp xamarin.forms uipangesturerecognizer

我的问题是关于Xamarin.Forms上的PanGestureRecognizer,特别是关于UWP的问题。平移手势很有效,菜单可以滑入和滑出,但如果将鼠标光标移动到应用程序窗口之外,则不会触发GestureStatus.Canceled或GestureStatus.Completed。我已经简化了下面的代码,因为它并不重要。平移手势正常工作,菜单随着平底锅滑入和滑出。问题是,如果将光标移到应用程序窗口之外,它不会触发任何内容。

以下代码:

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;
        }
    }

提前致谢!

2 个答案:

答案 0 :(得分:2)

  

如果将鼠标光标移动到应用程序窗口之外,则不会触发GestureStatus.Canceled或GestureStatus.Completed。我已经简化了下面的代码,因为它并不重要。平移手势正常工作,菜单随着平底锅滑入和滑出。问题是,如果将光标移到应用程序窗口之外,它不会触发任何内容。

我已经测试了您的代码并重现了该问题。我试图在源代码中找到问题的原因。我找到了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);
}

当您PanCompletePointerExited等时,将调用ManipulationCompleted方法。但是当指针退出时,它尚未被调用。然后我尝试在uwp本机项目中测试PointerExitedManipulationCompleted事件。两者都运作正常。

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

因此,xamarin可能存在一些问题。

答案 1 :(得分:0)

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

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