Пример #1
0
        public override void TouchesCancelled(NSSet touches, UIEvent evt)
        {
            try
            {
                var isHandledOrBubblingInManaged = default(bool);
                foreach (UITouch touch in touches)
                {
                    var pt   = TransientNativePointer.Get(this, touch);
                    var args = new PointerRoutedEventArgs(pt.Id, touch, evt, this);

                    // Note: We should have raise either PointerCaptureLost or PointerCancelled here depending of the reason which
                    //		 drives the system to bubble a lost. However we don't have this kind of information on iOS, and it's
                    //		 usually due to the ScrollView which kicks in. So we always raise the CaptureLost which is the behavior
                    //		 on UWP when scroll starts (even if no capture are actives at this time).

                    isHandledOrBubblingInManaged |= OnNativePointerCancel(args, isSwallowedBySystem: true);

                    pt.Release(this);
                }

                if (!isHandledOrBubblingInManaged)
                {
                    // Continue native bubbling up of the event
                    base.TouchesCancelled(touches, evt);
                }

                NotifyParentTouchesManagersManipulationEnded();
            }
            catch (Exception e)
            {
                Application.Current.RaiseRecoverableUnhandledException(e);
            }
        }
Пример #2
0
        public override void TouchesMoved(NSSet touches, UIEvent evt)
        {
            try
            {
                var isHandledOrBubblingInManaged = default(bool);
                foreach (UITouch touch in touches)
                {
                    var pt            = TransientNativePointer.Get(this, touch);
                    var args          = new PointerRoutedEventArgs(pt.Id, touch, evt, this);
                    var isPointerOver = touch.IsTouchInView(this);

                    // This is acceptable to keep that flag in a kind-of static way, since iOS do "implicit captures",
                    // a potential move will be dispatched to all elements "registered" on this "TransientNativePointer".
                    pt.HadMove = true;

                    // As we don't have enter/exit equivalents on iOS, we have to update the IsOver on each move
                    // Note: Entered / Exited are raised *before* the Move (Checked using the args timestamp)
                    isHandledOrBubblingInManaged |= OnNativePointerMoveWithOverCheck(args, isPointerOver);
                }

                if (!isHandledOrBubblingInManaged)
                {
                    // Continue native bubbling up of the event
                    base.TouchesMoved(touches, evt);
                }
            }
            catch (Exception e)
            {
                Application.Current.RaiseRecoverableUnhandledException(e);
            }
        }
Пример #3
0
            public static TransientNativePointer Get(UIElement element, UITouch touch)
            {
                if (!_instances.TryGetValue(touch.Handle, out var id))
                {
                    _instances[touch.Handle] = id = new TransientNativePointer(touch.Handle);
                }

                id._leases.Add(element);

                return(id);
            }
Пример #4
0
        public override void TouchesEnded(NSSet touches, UIEvent evt)
        {
            try
            {
                var isHandledOrBubblingInManaged = default(bool);
                foreach (UITouch touch in touches)
                {
                    var pt   = TransientNativePointer.Get(this, touch);
                    var args = new PointerRoutedEventArgs(pt.Id, touch, evt, this);

                    if (!pt.HadMove)
                    {
                        // The event will bubble in managed, so as this flag is "pseudo static", make sure to raise it only once.
                        pt.HadMove = true;

                        // On iOS if the gesture is really fast (like a flick), we can get only 'down' and 'up'.
                        // But on UWP it seems that we always have a least one move (for fingers and pen!), and even internally,
                        // the manipulation events are requiring at least one move to kick-in.
                        // Here we are just making sure to raise that event with the final location.
                        // Note: In case of multi-touch we might raise it unnecessarily, but it won't have any negative impact.
                        // Note: We do not consider the result of that move for the 'isHandledOrBubblingInManaged'
                        //		 as it's kind of un-related to the 'up' itself.
                        var mixedArgs = new PointerRoutedEventArgs(previous: pt.DownArgs, current: args);
                        OnNativePointerMove(mixedArgs);
                    }

                    isHandledOrBubblingInManaged |= OnNativePointerUp(args);
                    isHandledOrBubblingInManaged |= OnNativePointerExited(args);

                    pt.Release(this);
                }

                if (!isHandledOrBubblingInManaged)
                {
                    // Continue native bubbling up of the event
                    base.TouchesEnded(touches, evt);
                }

                NotifyParentTouchesManagersManipulationEnded();
            }
            catch (Exception e)
            {
                Application.Current.RaiseRecoverableUnhandledException(e);
            }
        }
Пример #5
0
        public override void TouchesBegan(NSSet touches, UIEvent evt)
        {
            if (!ArePointersEnabled)
            {
                return;                 // Will also prevent subsequents events
            }

            try
            {
                if (ManipulationMode == ManipulationModes.None)
                {
                    // If manipulation mode is None, we make sure to disable scrollers directly on pointer pressed
                    NotifyParentTouchesManagersManipulationStarted();
                }

                var isHandledOrBubblingInManaged = default(bool);
                foreach (UITouch touch in touches)
                {
                    var pt   = TransientNativePointer.Get(this, touch);
                    var args = new PointerRoutedEventArgs(pt.Id, touch, evt, this);

                    // We set the DownArgs only for the top most element (a.k.a. OriginalSource)
                    pt.DownArgs ??= args;

                    if (pt.LastManagedOnlyFrameId >= args.FrameId)
                    {
                        continue;
                    }

                    // We don't have any enter on iOS for touches, so we explicitly generate one on down.
                    // That event args is requested to bubble in managed code only (args.CanBubbleNatively = false),
                    // so we follow the same sequence as UWP (the whole tree gets entered before the pressed),
                    // and we make sure that the event will bubble through the whole tree, no matter if the Pressed event is handle or not.
                    // Note: Parents will also try to raise the "Enter" but they will be silent since the pointer is already considered as pressed.
                    args.CanBubbleNatively = false;
                    OnNativePointerEnter(args);

                    isHandledOrBubblingInManaged |= OnNativePointerDown(args.Reset());

                    if (isHandledOrBubblingInManaged)
                    {
                        pt.LastManagedOnlyFrameId = args.FrameId;
                    }
                }

                /*
                 * If we do not propagate the "TouchesBegan" to the parents (if isHandledOrBubblingInManaged),
                 * they won't receive the "TouchesMoved" nor the "TouchesEnded".
                 *
                 * It means that if a control (like the Button) handles the "Pressed" (or the "Entered")
                 * parent won't receive any touch event.
                 *
                 * To avoid that, we never prevent the base.TouchesBegan, but instead we keep track of the FrameId,
                 * and then in parents control filter out events that was already raised in managed.
                 */

                // Continue native bubbling up of the event
                base.TouchesBegan(touches, evt);
            }
            catch (Exception e)
            {
                Application.Current.RaiseRecoverableUnhandledException(e);
            }
        }
Пример #6
0
        public override void TouchesEnded(NSSet touches, UIEvent evt)
        {
            /* Note: Here we have a mismatching behavior with UWP, if the events bubble natively we're going to get
             *               (with Ctrl_02 is a child of Ctrl_01):
             *                              Ctrl_02: Released
             *                                               Exited
             *                              Ctrl_01: Released
             *                                               Exited
             *
             *              While on UWP we will get:
             *                              Ctrl_02: Released
             *                              Ctrl_01: Released
             *                              Ctrl_02: Exited
             *                              Ctrl_01: Exited
             *
             *              However, to fix this is would mean that we handle all events in managed code, but this would
             *              break lots of control (ScrollViewer) and ability to easily integrate an external component.
             */

            try
            {
                var isHandledOrBubblingInManaged = default(bool);
                foreach (UITouch touch in touches)
                {
                    var pt   = TransientNativePointer.Get(this, touch);
                    var args = new PointerRoutedEventArgs(pt.Id, touch, evt, this);

                    if (!pt.HadMove)
                    {
                        // The event will bubble in managed, so as this flag is "pseudo static", make sure to raise it only once.
                        pt.HadMove = true;

                        // On iOS if the gesture is really fast (like a flick), we can get only 'down' and 'up'.
                        // But on UWP it seems that we always have a least one move (for fingers and pen!), and even internally,
                        // the manipulation events are requiring at least one move to kick-in.
                        // Here we are just making sure to raise that event with the final location.
                        // Note: In case of multi-touch we might raise it unnecessarily, but it won't have any negative impact.
                        // Note: We do not consider the result of that move for the 'isHandledOrBubblingInManaged'
                        //		 as it's kind of un-related to the 'up' itself.
                        var mixedArgs = new PointerRoutedEventArgs(previous: pt.DownArgs, current: args);
                        OnNativePointerMove(mixedArgs);
                    }

                    isHandledOrBubblingInManaged |= OnNativePointerUp(args);

                    if (isHandledOrBubblingInManaged)
                    {
                        // Like for the Down, we need to manually generate an Exited.
                        // This is expected to be done by the RootVisual, except if the "up" has been handled
                        // (in order to ensure the "up" has been fully processed, including gesture recognition).
                        // In that case we need to sent it by our-own directly from teh element that has handled the event.

                        RootVisual.ProcessPointerUp(args, isAfterHandledUp: true);
                    }

                    pt.Release(this);
                }

                if (!isHandledOrBubblingInManaged)
                {
                    // Continue native bubbling up of the event
                    base.TouchesEnded(touches, evt);
                }

                NotifyParentTouchesManagersManipulationEnded();
            }
            catch (Exception e)
            {
                Application.Current.RaiseRecoverableUnhandledException(e);
            }
        }
Пример #7
0
        public override void TouchesBegan(NSSet touches, UIEvent evt)
        {
            if (IsPointersSuspended)
            {
                return;                 // Will also prevent subsequents events
            }

            /* Note: Here we have a mismatching behavior with UWP, if the events bubble natively we're going to get
             *               (with Ctrl_02 is a child of Ctrl_01):
             *                              Ctrl_02: Entered
             *                                               Pressed
             *                              Ctrl_01: Entered
             *                                               Pressed
             *
             *              While on UWP we will get:
             *                              Ctrl_02: Entered
             *                              Ctrl_01: Entered
             *                              Ctrl_02: Pressed
             *                              Ctrl_01: Pressed
             *
             *              However, to fix this is would mean that we handle all events in managed code, but this would
             *              break lots of control (ScrollViewer) and ability to easily integrate an external component.
             */

            try
            {
                if (ManipulationMode == ManipulationModes.None)
                {
                    // If manipulation mode is None, we make sure to disable scrollers directly on pointer pressed
                    NotifyParentTouchesManagersManipulationStarted();
                }

                var isHandledOrBubblingInManaged = default(bool);
                foreach (UITouch touch in touches)
                {
                    var pt   = TransientNativePointer.Get(this, touch);
                    var args = new PointerRoutedEventArgs(pt.Id, touch, evt, this);

                    // We set the DownArgs only for the top most element (a.k.a. OriginalSource)
                    pt.DownArgs ??= args;

                    if (pt.LastManagedOnlyFrameId >= args.FrameId)
                    {
                        continue;
                    }

                    isHandledOrBubblingInManaged |= OnNativePointerEnter(args);
                    isHandledOrBubblingInManaged |= OnNativePointerDown(args);

                    if (isHandledOrBubblingInManaged)
                    {
                        pt.LastManagedOnlyFrameId = args.FrameId;
                    }
                }

                /*
                 * If we do not propagate the "TouchesBegan" to the parents (if isHandledOrBubblingInManaged),
                 * they won't receive the "TouchesMoved" nor the "TouchesEnded".
                 *
                 * It means that if a control (like the Button) handles the "Pressed" (or the "Entered")
                 * parent won't receive any touch event.
                 *
                 * To avoid that, we never prevent the base.TouchesBegan, but instead we keep track of the FrameId,
                 * and then in parents control filter out events that was already raised in managed.
                 */

                // Continue native bubbling up of the event
                base.TouchesBegan(touches, evt);
            }
            catch (Exception e)
            {
                Application.Current.RaiseRecoverableUnhandledException(e);
            }
        }