Pregunta

¿Es posible cambiar la cantidad que se desplaza WPF ScrollViewer? Simplemente me pregunto si es posible cambiar el visor de desplazamiento para que, al usar la rueda del mouse o las flechas del visor de desplazamiento, se pueda cambiar la cantidad de desplazamiento incremental.

¿Fue útil?

Solución

La respuesta corta es: no hay forma de hacerlo sin escribir un código de desplazamiento personalizado, pero no dejes que eso te asuste, no es tan difícil.

El ScrollViewer funciona desplazándose utilizando unidades físicas (es decir, píxeles) o interactuando con una implementación IScrollInfo para utilizar unidades lógicas. Esto se controla mediante la configuración la propiedad CanContentScroll donde un valor de falso significa '' desplazar el contenido usando unidades físicas '' y un valor de verdadero significa "desplazar el contenido lógicamente".

Entonces, ¿cómo desplaza ScrollViewer el contenido lógicamente? Al comunicarse con una implementación IScrollInfo. Así es como podría asumir exactamente cuánto se desplaza el contenido de su panel cuando alguien realiza una acción lógica. Consulte la documentación de IScrollInfo para obtener una lista de todas las unidades lógicas de medición que se pueden solicitar para desplazarse, pero como mencionó la rueda del mouse, le interesarán principalmente los métodos MouseWheelUp / Down / Left / Right.

Otros consejos

Aquí hay una clase WPF ScrollViewer simple, completa y funcional que tiene una propiedad SpeedFactor de datos enlazables para ajustar la sensibilidad de la rueda del mouse. Establecer SpeedFactor en 1.0 significa un comportamiento idéntico al ScrollViewer de WPF. El valor predeterminado para la propiedad de dependencia es 2.5 , lo que permite un desplazamiento de la rueda muy rápido.

Por supuesto, también puede crear funciones útiles adicionales al vincular la propiedad SpeedFactor en sí misma, es decir, para permitir fácilmente al usuario controlar el multiplicador.

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

Demostración completa de XAML del 'desplazamiento rápido de la rueda del mouse' de alrededor de 3200 elementos de datos:

<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>

Rueda rápida del mouse:

 ingrese la descripción de la imagen aquí

Puede implementar un comportamiento en el visor de desplazamiento. En mi caso, CanContentScroll no funcionó. La solución a continuación funciona para desplazarse con la rueda del mouse y arrastrar la barra de desplazamiento.

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(
<ScrollViewer MaxHeight="248"
              VerticalScrollBarVisibility="Auto">
    <i:Interaction.Behaviors>
        <behaviors:StepSizeBehavior StepSize="62" />
    </i:Interaction.Behaviors>
quot;{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); } }

Lo usarías así:

<*>

Hice esto para asegurar números enteros en scrollbar1.ValueChanged:

scrollbar1.Value = Math.Round(scrollbar1.Value, 0, MidpointRounding.AwayFromZero)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top