Подтвердить что ты не робот

Количество прокрутки ScrollViewer Wpf

Можно ли изменить количество прокрутки прокрутки WPF ScrollViewer? Я просто задаюсь вопросом, можно ли изменить scrollviewer так, чтобы при использовании колеса мыши или стрелок scrollviewer количество инкрементной прокрутки можно было изменить.

4b9b3361

Ответ 1

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

ScrollViewer либо работает путем прокрутки с использованием физических единиц (то есть пикселей), либо путем взаимодействия с реализацией IScrollInfo для использования логических единиц. Это контролируется параметром свойство CanContentScroll, где значение false означает "прокрутка содержимого с использованием физических единиц", а значение true означает "прокрутка" контент логически ".

Итак, как ScrollViewer логически прокручивает контент? Обмениваясь информацией с реализацией IScrollInfo. Так, чтобы вы могли точно определить, сколько содержимого вашей панели прокручивается, когда кто-то выполняет логическое действие. Взгляните на документацию для IScrollInfo, чтобы получить список всех логических единиц измерения, которые могут запрашиваться для прокрутки, но так как вы упомянули мы будем в основном интересоваться методами MouseWheelUp/Down/Left/Right.

Ответ 2

Вот простой, полный и рабочий класс WPF ScrollViewer, который имеет свойство привязки данных SpeedFactor для настройки чувствительности колеса мыши. Установка SpeedFactor на 1.0 означает поведение, идентичное WPF ScrollViewer. Значением по умолчанию для свойства зависимости является 2,5, что обеспечивает очень быструю прокрутку колес.

Конечно, вы также можете создавать дополнительные полезные функции, связываясь с самим свойством SpeedFactor, т.е. легко разрешать пользователю управлять множителем.

public class WheelSpeedScrollViewer : ScrollViewer
{
    public static readonly DependencyProperty SpeedFactorProperty =
        DependencyProperty.Register(nameof(SpeedFactor),
                                    typeof(Double),
                                    typeof(WheelSpeedScrollViewer),
                                    new PropertyMetadata(2.5));

    public Double SpeedFactor
    {
        get { return (Double)GetValue(SpeedFactorProperty); }
        set { SetValue(SpeedFactorProperty, value); }
    }

    protected override void OnPreviewMouseWheel(MouseWheelEventArgs e)
    {
        if (!e.Handled && 
            ScrollInfo is ScrollContentPresenter scp &&
            ComputedVerticalScrollBarVisibility == Visibility.Visible)
        {
            scp.SetVerticalOffset(VerticalOffset - e.Delta * SpeedFactor);
            e.Handled = true;
        }
    }
};

Завершите демонстрацию XAML "быстрой прокрутки колесика мыши", включающую около 3200 элементов данных:

примечание: ссылка на mscorlib предназначена только для доступа к демонстрационным данным.

<UserControl x:Class="RemoveDuplicateTextLines.FastScrollDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MyApp"
    xmlns:sys="clr-namespace:System;assembly=mscorlib">

    <local:WheelSpeedScrollViewer VerticalScrollBarVisibility="Auto">
        <ListBox ItemsSource="{Binding Source={x:Type sys:Object},Path=Assembly.DefinedTypes}" />
    </local:WheelSpeedScrollViewer>

</UserControl>

Быстрое колесо мыши:

enter image description here

Ответ 3

Вы можете реализовать поведение в scrollviewer. В моем случае CanContentScroll не работал. Решение ниже работает для прокрутки с помощью колеса мыши, а также для прокрутки полосы прокрутки.

public class StepSizeBehavior : Behavior<ScrollViewer>
{
    public int StepSize { get; set; }

    #region Attach & Detach
    protected override void OnAttached()
    {
        CheckHeightModulesStepSize();
        AssociatedObject.ScrollChanged += AssociatedObject_ScrollChanged;
        base.OnAttached();
    }

    protected override void OnDetaching()
    {
        AssociatedObject.ScrollChanged -= AssociatedObject_ScrollChanged;
        base.OnDetaching();
    }
    #endregion

    [Conditional("DEBUG")]
    private void CheckHeightModulesStepSize()
    {
        var height = AssociatedObject.Height;
        var remainder = height%StepSize;
        if (remainder > 0)
        {
            throw new ArgumentException($"{nameof(StepSize)} should be set to a value by which the height van be divised without a remainder.");
        }
    }

    private void AssociatedObject_ScrollChanged(object sender, ScrollChangedEventArgs e)
    {
        const double stepSize = 62;
        var scrollViewer = (ScrollViewer)sender;
        var steps = Math.Round(scrollViewer.VerticalOffset / stepSize, 0);
        var scrollPosition = steps * stepSize;
        if (scrollPosition >= scrollViewer.ScrollableHeight)
        {
            scrollViewer.ScrollToBottom();
            return;
        }
        scrollViewer.ScrollToVerticalOffset(scrollPosition);
    }
}

Вы бы использовали его следующим образом:

<ScrollViewer MaxHeight="248"
              VerticalScrollBarVisibility="Auto">
    <i:Interaction.Behaviors>
        <behaviors:StepSizeBehavior StepSize="62" />
    </i:Interaction.Behaviors>

Ответ 4

Я сделал это, чтобы обеспечить целые числа на scrollbar1.ValueChanged:

scrollbar1.Value = Math.Round(scrollbar1.Value, 0, MidpointRounding.AwayFromZero)