Ограничить событие клика по кнопке при прокрутке

Вопрос или проблема

У меня есть пользовательский элемент управления списком (не производный от ListView) с поддержкой DataTemplate и различными интерактивными функциями. Чтобы управлять прокруткой scrollview, я обработал режим манипуляции для содержимого scrollview. Если пользователь загружает кнопку внутри шаблона и взаимодействует с ней во время прокрутки, список прокручивается, но событие нажатия кнопки также срабатывает при отпускании касания. Если я не обрабатываю манипуляцию, нажатие кнопки не срабатывает.
Примечание: У меня нет доступа к этим кнопкам внутри моего источника

Как ограничить срабатывание этой кнопки, если я обрабатываю режим манипуляции содержимого scrollview.

    <ScrollViewer>
        <StackPanel x:Name="stack">
            <Grid Height="100">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="50"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Button Grid.Column="0">Нажмите здесь</Button>
                <Border Background="AntiqueWhite" Grid.Column="1"/>
            </Grid>
            <Grid Height="100">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="50"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Button Grid.Column="0">Нажмите здесь</Button>
                <Border Background="Aqua" Grid.Column="1"/>
            </Grid>
            <Grid Height="100">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="50"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Button Grid.Column="0">Нажмите здесь</Button>
                <Border Background="AntiqueWhite" Grid.Column="1"/>
            </Grid>
...
...
....
                <Grid Height="100">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="50"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <Button Grid.Column="0">Нажмите здесь</Button>
                    <Border Background="AntiqueWhite" Grid.Column="1"/>
                </Grid>
                <Grid Height="100">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="50"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    <Button Grid.Column="0">Нажмите здесь</Button>
                    <Border Background="Aqua" Grid.Column="1"/>
                </Grid>
            </Grid>
        </StackPanel>
    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)
                text.Background = new SolidColorBrush(Colors.Red);
            else
                text.Background = new SolidColorBrush(Colors.Green);
    
            changed = !changed;
        }
    }

Я пытался сделать следующее, чтобы достичь этого, но ничего не сработало.

 - Пытался установить режим манипуляции в системный и сделать свою настройку функционала взаимодействия, используя AddHandler для события манипуляции, ни одно из событий не сработало.
 - Обрабатывал события нажатия указателя в содержимом scrollview.
 - Пытался захватить указатель при нажатии, отпускании и движении.
 - Установил IsTapEnabled в false.
 - Установил e.handled как false в манипуляции с дельтой при режиме манипуляции: Все.
 - Использовал CancelDirectManipulation для Textblock при нажатии указателя.
 - Предложил пользователю - обойти это с проверкой прокрутки в нажатии кнопки, но не доволен предложением.

Ответ или решение

Ограничение события нажатия кнопки при прокрутке: Решение проблемы

В этом ответе мы рассмотрим, как можно ограничить срабатывание события нажатия кнопки в элементах управления, которые зависят от взаимодействия с прокруткой. Эта проблема возникает, когда пользователь пытается взаимодействовать с кнопками, находящимися в списках с прокруткой, и непреднамеренно срабатывают события клика при отпускании касания.

Проблема

Вы работаете с пользовательским управлением списка, в который входят элементы с кнопками, и столкнулись с тем, что при взаимодействии с этими кнопками в процессе прокрутки, событие нажатия кнопки срабатывает даже после того, как пользователь начал прокрутку. При этом, ваши усилия по управлению режимом манипуляций не обеспечивают блокировку клика.

Описание имеющегося кода

В вашем коде уже настроены необходимые обработчики событий для управления манипуляциями:

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

Однако нажатие кнопки при отпускании может сработать, если прокрутка была достаточно незначительной. Этот механизм не учитывает состояние прокрутки.

Решение

Для решения проблемы вам необходимо реализовать механизм, который предотвращает срабатывание клика, если прокрутка произошла на определённое значение. Это можно достигнуть с помощью следующего подхода:

  1. Отслеживание состояния прокрутки: Вводим переменную, которая будет отслеживать расстояние прокрутки, чтобы определить, было ли срабатывание клика ошибкой при взаимодействии.

  2. Проверка расстояния перед выполнением кнопки: В обработчике события нажатия проверяем, было ли движение достаточно заметным, чтобы считать его прокруткой.

Пример кода

Вот пример реализации предложенного решения:

private double previousOffset;
private double scrollThreshold = 10; // Определите порог прокрутки

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; // Игнорируем события мыши
    }

    double newOffset = this.previousOffset - e.Cumulative.Translation.Y;
    this.scrollview.ScrollToVerticalOffset(newOffset);
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    var button = sender as Button;
    var position = button.TransformToVisual(this.scrollview).Transform(new Point(0, 0)).Y;

    if (Math.Abs(previousOffset - position) >= scrollThreshold)
    {
        // Если прокрутка была значительной, игнорируем клик
        return;
    }

    // Обработка клика
    if (changed)
        text.Background = new SolidColorBrush(Colors.Red);
    else
        text.Background = new SolidColorBrush(Colors.Green);

    changed = !changed;
}

Заключение

Обеспечение корректного срабатывания кнопок в контексте прокрутки — это важная задача для улучшения пользовательского опыта. Используя предложенный подход с отслеживанием расстояния прокрутки и соблёгшая пороговых значений, можно предотвратить непреднамеренные клики. Тестируйте ваше решение на различных устройствах, чтобы удостовериться в правильности работы.

Эта техника ограничивает случайные нажатия и улучшает взаимодействие с интерфейсом, что важно для разработчиков, стремящихся создать качественные приложения.

Оцените материал
Добавить комментарий

Капча загружается...