Domanda

È possibile modificare la quantità di scorrimento di WPF ScrollViewer? Mi chiedo semplicemente se è possibile cambiare il visualizzatore di scorrimento in modo che quando si utilizza la rotellina del mouse o le frecce del visualizzatore di scorrimento, è possibile modificare la quantità di scorrimento incrementale.

È stato utile?

Soluzione

La risposta breve è: non c'è modo di farlo senza scrivere un codice di scorrimento personalizzato, ma non lasciare che ti spaventi non è poi così difficile.

ScrollViewer funziona scorrendo usando unità fisiche (cioè pixel) o impegnandosi con un'implementazione di IScrollInfo per usare unità logiche. Questo è controllato dall'impostazione la proprietà CanContentScroll dove un valore di false significa "scorrere il contenuto usando le unità fisiche" e un valore di mezzi veri " scorrere il contenuto logicamente " ;.

Quindi, come fa ScrollViewer a scorrere il contenuto logicamente? Comunicando con un'implementazione IScrollInfo. Quindi è così che potresti assumere esattamente quanto scorre il contenuto del tuo pannello quando qualcuno esegue un'azione logica. Dai un'occhiata alla documentazione di IScrollInfo per ottenere un elenco di tutte le unità logiche di misura che possono essere richieste per scorrere, ma poiché hai citato la rotellina del mouse, sarai principalmente interessato ai metodi MouseWheelUp / Giù / Sinistra / Destra.

Altri suggerimenti

Ecco una WPF ScrollViewer semplice, completa e funzionante che ha una proprietà SpeedFactor vincolante i dati per regolare la sensibilità della rotellina del mouse. L'impostazione di SpeedFactor su 1.0 significa un comportamento identico al ScrollViewer di WPF. Il valore predefinito per la proprietà di dipendenza è 2.5 , che consente lo scorrimento delle ruote molto veloce.

Ovviamente, puoi anche creare funzionalità utili aggiuntive vincolando la proprietà SpeedFactor stessa, ovvero per consentire all'utente di controllare facilmente il moltiplicatore.

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

Demo completa XAML di "scorrimento rapido della rotellina del mouse" di circa 3200 elementi di dati:

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

Rotellina veloce del mouse:

 inserisci qui la descrizione dell'immagine

È possibile implementare un comportamento sullo scrollviewer. Nel mio caso CanContentScroll non ha funzionato. La soluzione seguente funziona per lo scorrimento con la rotellina del mouse e per trascinare la barra di scorrimento.

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 useresti in questo modo:

<*>

L'ho fatto per garantire numeri interi su scrollbar1.ValueChanged:

scrollbar1.Value = Math.Round(scrollbar1.Value, 0, MidpointRounding.AwayFromZero)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top