How to restrict scrolling and panning with single finger and enable with two fingers in UWP ScrollViewer using touch screen?

Imman Kumar 6 Reputation points
2023-03-27T06:02:13.86+00:00

Hi,

In an UWP application, I am having a ScrollViewer in the XAML which contains a StackPanel as Content. In that StackPanel there are some images.

XAML:

<Grid>
        <ScrollViewer x:Name="scrollView" ZoomMode="Enabled">
            <StackPanel>
                <Image Source="Assets/ScrollView.jpeg"/>
                <Image Source="Assets/ScrollView.jpeg"/>
                <Image Source="Assets/ScrollView.jpeg"/>
                <Image Source="Assets/ScrollView.jpeg"/>
            </StackPanel>
        </ScrollViewer>
    </Grid>

Code behind:

public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            this.InitializeComponent();
            this.scrollView.AddHandler(UIElement.PointerPressedEvent, new PointerEventHandler(scrollView_PointerPressed), true);
            this.scrollView.AddHandler(UIElement.PointerReleasedEvent, new PointerEventHandler(scrollView_PointerReleased), true);
            this.scrollView.AddHandler(UIElement.PointerCanceledEvent, new PointerEventHandler(scrollView_PointerCanceled), true);
        }

        int numberOfContacts = 0;
        private void scrollView_PointerPressed(object sender, PointerRoutedEventArgs e)
        {
            if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch)
            {
                numberOfContacts++;
                System.Diagnostics.Debug.WriteLine($"Pressed -> {numberOfContacts}");
                if (numberOfContacts == 1)
                {
                    (scrollView.Content as UIElement).ManipulationMode &= ~ManipulationModes.System;
                }
                else if(numberOfContacts > 1)
                {
                    (scrollView.Content as UIElement).ManipulationMode |= ManipulationModes.System;
                }
            }
        }

        private void scrollView_PointerReleased(object sender, PointerRoutedEventArgs e)
        {
            if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch)
            {
                numberOfContacts--;
                System.Diagnostics.Debug.WriteLine($"Released -> {numberOfContacts}");
                (scrollView.Content as UIElement).ManipulationMode |= ManipulationModes.System;
            }
        }

        private void scrollView_PointerCanceled(object sender, PointerRoutedEventArgs e)
        {
            if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch)
            {
                numberOfContacts--;
                System.Diagnostics.Debug.WriteLine($"Cancelled -> {numberOfContacts}");
                (scrollView.Content as UIElement).ManipulationMode |= ManipulationModes.System;
            }
        }
    }

I want to disable scrolling and panning with single finger and to enable them with two or more fingers. So I have used the Pointer events to track the number of fingers that are in contact with the touch screen. Here, the Pointer pressed event is raised properly when a contact is made. But when I scrolled the view the Pointer released event is not raised as expected.

How can I track the active number of touch contact with the screen to restrict scrolling with single finger?

Xamarin
Xamarin
A Microsoft open-source app platform for building Android and iOS apps with .NET and C#.
5,336 questions
Universal Windows Platform (UWP)
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Roy Li - MSFT 32,921 Reputation points Microsoft Vendor
    2023-03-28T07:47:45.71+00:00

    Hello,

    Welcome to Microsoft Q&A!

    How can I track the active number of touch contact with the screen to restrict scrolling with single finger?

    Currently, there is no built-in API that could directly do this. I've tested your code and I could reproduce the behavior you mentioned. After some test, I've found a solution to your question. What you need to do is just handle an extra pointer event called UIElement.PointerCaptureLost Event. The event will be fired when pointer capture previously held by this element moves to another element or elsewhere. This is the also the reason why the pointer release event is not fired.

    After handling this event and do the same logic as well as PointerReleasedEvent and PointerCanceledEvent, you should be able to get correct finger numbers on touch.

    Update:

    I've tested the code and update it again after getting your reply. Please handle the UIElement.PointerExited Event as well. And make a check for the numberOfContacts. Please note one thing, if you finger moves out of the app but still in touch of the screen, this will not be counted as a touched finger. Now the code should do what you want at the beginning. In my testing it will disable scrolling and panning with single finger and to enable them with two or more fingers.

    Here is the code:

      public MainPage()
            {
                this.InitializeComponent();
                this.scrollView.AddHandler(UIElement.PointerPressedEvent, new PointerEventHandler(scrollView_PointerPressed), true);
                this.scrollView.AddHandler(UIElement.PointerReleasedEvent, new PointerEventHandler(scrollView_PointerReleased), true);
                this.scrollView.AddHandler(UIElement.PointerCanceledEvent, new PointerEventHandler(scrollView_PointerCanceled), true);
                this.scrollView.AddHandler(UIElement.PointerCaptureLostEvent, new PointerEventHandler(scrollView_PointerCaptureLost), true);
                this.scrollView.AddHandler(UIElement.PointerExitedEvent, new PointerEventHandler(scrollView_PointerExited), true);
                
            }
    
            int numberOfContacts = 0;
            private void scrollView_PointerPressed(object sender, PointerRoutedEventArgs e)
            {
                if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch)
                {
                    numberOfContacts++;
                    System.Diagnostics.Debug.WriteLine($"Pressed -> {numberOfContacts}");
                    if (numberOfContacts == 1)
                    {
                        (scrollView.Content as UIElement).ManipulationMode &= ~ManipulationModes.System;
                    }
                    else if (numberOfContacts > 1)
                    {
                        (scrollView.Content as UIElement).ManipulationMode |= ManipulationModes.System;
                    }
                }
            }
    
            private void scrollView_PointerReleased(object sender, PointerRoutedEventArgs e)
            {
                if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch)
                {
                    if (numberOfContacts > 0)
                    {
                        numberOfContacts--;
                    }
                    System.Diagnostics.Debug.WriteLine($"Released -> {numberOfContacts}");
                    (scrollView.Content as UIElement).ManipulationMode |= ManipulationModes.System;
                }
            }
    
            private void scrollView_PointerCanceled(object sender, PointerRoutedEventArgs e)
            {
                if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch)
                {
                    if (numberOfContacts > 0)
                    {
                        numberOfContacts--;
                    }
                    System.Diagnostics.Debug.WriteLine($"Cancelled -> {numberOfContacts}");
                    (scrollView.Content as UIElement).ManipulationMode |= ManipulationModes.System;
                }
            }
    
            private void scrollView_PointerCaptureLost(object sender, PointerRoutedEventArgs e)
            {
                if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch)
                {
                    if (numberOfContacts > 0)
                    {
                        numberOfContacts--;
                    }
                    System.Diagnostics.Debug.WriteLine($"Capture lost -> {numberOfContacts}");
                    (scrollView.Content as UIElement).ManipulationMode |= ManipulationModes.System;
                }
            }
    
            private void scrollView_PointerExited(object sender, PointerRoutedEventArgs e)
            {
                if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Touch)
                {
                    if (numberOfContacts>0) 
                    {
                        numberOfContacts--;
                    }
                    System.Diagnostics.Debug.WriteLine($"Pointer Exited -> {numberOfContacts}");
                    (scrollView.Content as UIElement).ManipulationMode |= ManipulationModes.System;
                }
            }
    

    Thank you.


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.