What event fires when user lifts finger from ScrollViewer on touch capable screens
Asked Answered
H

2

10

I'm finding that when I tap the ScrollViewer, the PointerPressed and PointerExited events fires as expected. But, if I scroll in any direction after touching the screen and lift my finger, no event fires except for PointerCaptureLost which prematurely fires as soon as I scroll.

When I capture the pointer ID and poll the status of the PointerPoint with a timer, the IsInContact flag remains true, even after I lift my finger after scrolling. It works as expected when I simply tap the screen.

ManipulationCompleted has the same effect as above, and I cannot use the ViewChanged event since this fires before I lift my finger.

Is this a bug or am I missing something here? Is there another way I can detect when a user has lifted their finger off the screen? This is driving me bananas.

Sample code below. You'll need to use the simulator in touch-mode or have a touch capable screen to test:

Code:

using System;
using Windows.UI.Input;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;

namespace App1
{
    public sealed partial class MainPage : Page
    {

        private readonly DispatcherTimer pointerTimer = new DispatcherTimer();
        private uint? CurrentPointerID; //container for the current pointer id when user makes contact with the screeen

        public MainPage()
        {
            this.InitializeComponent();

            scrollviewer.PointerPressed += scrollviewer_PointerPressed;
            scrollviewer.PointerMoved += scrollviewer_PointerMoved;
            scrollviewer.PointerExited += scrollviewer_PointerExited;
            scrollviewer.PointerReleased += scrollviewer_PointerReleased;
            scrollviewer.PointerCaptureLost += scrollviewer_PointerCaptureLost;
            scrollviewer.PointerCanceled += scrollviewer_PointerCanceled;


            pointerTimer.Tick += pointerTimer_Tick;
            pointerTimer.Interval = TimeSpan.FromMilliseconds(300);
            pointerTimer.Start();


        }

        #region ScrollViewer Events

        void scrollviewer_PointerMoved(object sender, PointerRoutedEventArgs e)
        {
            EventCalledTextBlock.Text = "Pointer Moved";
        }

        void scrollviewer_PointerExited(object sender, PointerRoutedEventArgs e)
        {
            EventCalledTextBlock.Text = "Pointer Exited";
        }

        void scrollviewer_PointerPressed(object sender, PointerRoutedEventArgs e)
        {
            CurrentPointerID = e.Pointer.PointerId;
            EventCalledTextBlock.Text = "Pointer Pressed";
        }

        void scrollviewer_PointerCanceled(object sender, PointerRoutedEventArgs e)
        {
            EventCalledTextBlock.Text = "Pointer Canceled";
        }

        void scrollviewer_PointerCaptureLost(object sender, PointerRoutedEventArgs e)
        {
            EventCalledTextBlock.Text = "Capture Lost";
        }

        void scrollviewer_PointerReleased(object sender, PointerRoutedEventArgs e)
        {
            EventCalledTextBlock.Text = "Pointer Released";
        }
        #endregion



        void pointerTimer_Tick(object sender, object e)
        {
            if (!CurrentPointerID.HasValue)
            {
                PollingTextBlock.Text = string.Empty;
                return;
            }

            try
            {
                var pointerPoint = PointerPoint.GetCurrentPoint(CurrentPointerID.Value);

                PollingTextBlock.Text = pointerPoint.IsInContact ? "Is In Contact" : "Not in Contact";
            }
            catch (Exception ex)
            {
                //This exception is raised when the user lifts finger without dragging.
                //assume finger is not in contact with screen
                PollingTextBlock.Text = "Not in Contact";
            }
        }

    }
}

XAML:

 <Page
    x:Class="App1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:App1"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}" Name="grid">
        <Grid.RowDefinitions>
            <RowDefinition Height="113*"/>
            <RowDefinition Height="655*"/>
        </Grid.RowDefinitions>
        <ScrollViewer x:Name="scrollviewer" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Visible" Grid.Row="1" >
            <Rectangle Fill="#FF3783CF" Height="100" Stroke="#FF33D851" Width="{Binding ElementName=grid, Path=ActualWidth}" Margin="100" StrokeThickness="4" />
        </ScrollViewer>
        <StackPanel Orientation="Vertical" Margin="45,25,0,0">
            <StackPanel Orientation="Horizontal">
            <TextBlock  HorizontalAlignment="Left" TextWrapping="Wrap" Text="Event Called:" VerticalAlignment="Top" FontSize="24" Margin="0,0,20,0"/>
            <TextBlock x:Name="EventCalledTextBlock" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="24"/>
        </StackPanel>
        <StackPanel Orientation="Horizontal">
            <TextBlock  HorizontalAlignment="Left" TextWrapping="Wrap" Text="Polling Value:" VerticalAlignment="Top" FontSize="24" Margin="0,0,20,0"/>
            <TextBlock x:Name="PollingTextBlock" HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" FontSize="24"/>
        </StackPanel>
    </StackPanel>

    </Grid>
</Page>
Hover answered 13/12, 2013 at 2:28 Comment(5)
Have you tried manipulation events rather than pointer events?Lashonda
Yes. It results in the same behavior as above where ManipulationCompleted is never called after scrolling.Hover
I wonder if the Rectangle inside your ScrollViewer is "eating up" your Pointer Released event.Mistiemistime
Good theory, however when I add the pointer events to the Rectangle via ((UIElement) scrollviewer.Content), they don't fire at all. Also setting the ManipulationMode on the Rectangle allows the PointerExit event on the Scrollviewer to be raised, however this seams to disable scrolling all together.Hover
Hm, I do remember reading in the MSDN docs that a PointerReleased event does not always have to fire. It gave several reasons why that would be the case. Found it. Check this out "Don't rely on PointerPressed and PointerReleased events always occurring in pairs. To function properly, your app must listen for and handle all events that represent likely conclusions to the Press action." Here's the link: msdn.microsoft.com/library/windows/apps/br208972Mistiemistime
C
1

I stumbled upon this question since I was struggling with a similar problem. I have a ScrollViewer which has several images in it and I wanted to know what images are shown at the moment the ScrollViewer stops moving...

In the end I did used the ScrollViewer.ViewChanged event. This event keeps triggering untill it has finished with scrolling.

I actually am only interested in the last of these events, but since there is no event that triggers only on that particular moment I need to respond to this one and check for myself if this is the appropriate moment to take actions.

I hope this helps.

ScrollViewer.ViewChanged event: https://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.xaml.controls.scrollviewer.viewchanged?f=255&MSPPError=-2147217396

Coelom answered 3/9, 2015 at 14:17 Comment(0)
I
0

I think you need to use the PointerReleased event. Refer to the following link: https://msdn.microsoft.com/library/windows/apps/br208279

Inspirit answered 1/9, 2015 at 21:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.