Wpf ScrollViewer Scroll Amount - PullRequest
       36

Wpf ScrollViewer Scroll Amount

14 голосов
/ 28 октября 2009

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

Ответы [ 4 ]

14 голосов
/ 29 октября 2009

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

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

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

2 голосов
/ 29 августа 2018

Вот простой, полный и работающий класс 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 элементов данных:

<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

1 голос
/ 06 марта 2017

Вы можете реализовать поведение на просмотрщике прокрутки. В моем случае 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>
0 голосов
/ 29 апреля 2017

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

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