Ranjith Kumar
Ranjith Kumar

Reputation: 1

Restrict button click event when scrolling

I have a custom list-type control (not derived from ListView) with DataTemplate support and various interactive features. To manage the scrollview’s scrolling, I’ve handled the Manipulation Mode for scrollview content. If a user loads a button inside the template and interacts with it while scrolling, the list scrolls but the button's click event also gets triggered upon touch release. If I don’t handle manipulation, the button click is not triggered.
Note : I don't have access to these button inside my source

How to restrict this button clicked if I handle manipulation mode of scrollview's content.

       <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50"/>
            <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Border Height="100" x:Name="borderControl">
                <TextBlock Text="Hello"/>
            </Border>
            <ScrollViewer x:Name="scrollview" Grid.Row="1">
                <StackPanel x:Name="stack">
                    <Grid Height="100">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="50"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <Button Grid.Column="0" Click="Button_Click">Click here</Button>
                        <Border Background="AntiqueWhite" Grid.Column="1"/>
                    </Grid>
                    <Grid Height="100">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="50"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>
                        <Button Grid.Column="0" Click="Button_Click">Click here</Button>
                        <Border Background="Aqua" Grid.Column="1"/>
                    </Grid>
     <Grid Height="100">
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="50"/>
             <ColumnDefinition Width="*"/>
         </Grid.ColumnDefinitions>
         <Button Grid.Column="0" Click="Button_Click">Click here</Button>
         <Border Background="AntiqueWhite" Grid.Column="1"/>
     </Grid>
     <Grid Height="100">
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="50"/>
             <ColumnDefinition Width="*"/>
         </Grid.ColumnDefinitions>
         <Button Grid.Column="0" Click="Button_Click">Click here</Button>
         <Border Background="Aqua" Grid.Column="1"/>
     </Grid>
        ...
        ...
        ....
                         <Grid Height="100">
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="50"/>
             <ColumnDefinition Width="*"/>
         </Grid.ColumnDefinitions>
         <Button Grid.Column="0" Click="Button_Click">Click here</Button>
         <Border Background="AntiqueWhite" Grid.Column="1"/>
     </Grid>
     <Grid Height="100">
         <Grid.ColumnDefinitions>
             <ColumnDefinition Width="50"/>
             <ColumnDefinition Width="*"/>
         </Grid.ColumnDefinitions>
         <Button Grid.Column="0" Click="Button_Click">Click here</Button>
         <Border Background="Aqua" Grid.Column="1"/>
     </Grid>
                    </StackPanel>
                </ScrollViewer>
            </Grid>


        public sealed partial class MainWindow : Window
    {
        private double previousOffset;
    
        public MainWindow()
        {
            this.InitializeComponent();
            this.stack.ManipulationMode = ManipulationModes.All;
            this.stack.ManipulationDelta += this.Content_ManipulationDelta;
            this.stack.ManipulationStarting += this.Content_ManipulationStarting;
    
        }
    
        private void Content_ManipulationStarting(object sender, ManipulationStartingRoutedEventArgs e)
        {
            this.previousOffset = this.scrollview.VerticalOffset;
        }
    
        private void Content_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
        {
            if (e.PointerDeviceType == Microsoft.UI.Input.PointerDeviceType.Mouse)
            {
                return;
            }
    
            this.scrollview.ScrollToVerticalOffset(this.previousOffset - e.Cumulative.Translation.Y);
        }
    
        bool changed;
    
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            if (changed)
                borderControl.Background = new SolidColorBrush(Colors.Red);
            else
                borderControl.Background = new SolidColorBrush(Colors.Green);
    
            changed = !changed;
        }
    }

I have tried the below things to achieve this, but none worked.

 - Tried Setting Manipulation mode to system and do my customization on interaction feature using AddHandler for Manipulation event, none of the event triggered.
 - Handled Pointer Presses event in Scrollview's content.
 - Tried Capturing pointer in Pressed, released and moved.
 - IsTapEnabled to false.
 - e.handled as false in Manipulation delta with Manipulation Mode: All.
 - CancelDirectManipulation for Textblock in pointer pressed.
 - Suggested to user - Workaround with scroll check in button click, but not happy with suggestion.

Upvotes: 0

Views: 65

Answers (1)

Andrew KeepCoding
Andrew KeepCoding

Reputation: 13761

Let me show you an example without manipulation events. At least works with the touch monitor on my laptop.

Shell.xaml

<Page
    x:Class="WinUIApp2.Shell"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="using:WinUIApp2"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"
    mc:Ignorable="d">

    <Page.Resources>
        <DataTemplate
            x:Key="ButtonItemTemplate"
            x:DataType="x:String">
            <Button
                Click="Button_Click"
                Content="{x:Bind}" />
        </DataTemplate>
    </Page.Resources>

    <ScrollViewer>
        <ItemsControl
            ItemTemplate="{StaticResource ButtonItemTemplate}"
            ItemsSource="{x:Bind Items}" />
    </ScrollViewer>

</Page>

Shell.xaml.cs

using Microsoft.UI.Xaml.Controls;
using System.Collections.ObjectModel;

namespace WinUIApp2;

public sealed partial class Shell : Page
{
    public Shell()
    {
        InitializeComponent();

        for (int i = 0; i < 100; i++)
        {
            Items.Add($"Item {i}");
        }
    }

    public ObservableCollection<string> Items { get; } = [];

    private void Button_Click(object sender, Microsoft.UI.Xaml.RoutedEventArgs e)
    {
        if (sender is not Button button)
        {
            return;
        }

        System.Diagnostics.Debug.WriteLine($"{button.Content} clicked.");
    }
}

Upvotes: 0

Related Questions