20

WPF ScrollViewerがスクロールする量を変更することは可能ですか?マウスホイールまたはscrollviewerの矢印を使用するときに、増分スクロールの量を変更できるように、scrollviewerを変更できるかどうか疑問に思っています。

4

5 に答える 5

17

簡単に言うと、カスタムのスクロールコードを記述せずにこれを行う方法はありませんが、それほど難しくはないので、怖がらせないでください。

ScrollViewerは、物理単位(つまり、ピクセル)を使用してスクロールするか、IScrollInfo実装を使用して論理単位を使用することによって機能します。これは、CanContentScrollプロパティの設定によって制御されます。ここで、falseの値は「物理単位を使用してコンテンツをスクロールする」ことを意味し、trueの値は「コンテンツを論理的にスクロールする」ことを意味します。

では、ScrollViewerはどのようにコンテンツを論理的にスクロールするのでしょうか。IScrollInfo実装と通信する。これが、誰かが論理的なアクションを実行したときにパネルのコンテンツがどれだけスクロールするかを正確に引き継ぐ方法です。IScrollInfoのドキュメントを参照して、スクロールを要求できる測定のすべての論理単位のリストを取得しますが、マウスホイールについて言及したので、MouseWheelUp / Down / Left/Rightメソッドに主に関心があります。

于 2009-10-29T02:43:36.703 に答える
9

これは、マウスホイールの感度を調整するためのデータバインド可能なプロパティを持つ、シンプルで完全で機能するWPFクラスです。 1.0に設定すると、WPFと同じ動作になります。依存関係プロパティのデフォルト値は2.5で、これにより非常に高速なホイールスクロールが可能になります。ScrollViewerSpeedFactorSpeedFactorScrollViewer

もちろん、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;
        }
    }
};

約3200のデータ項目の「高速マウスホイールスクロール」の完全なXAMLデモ:

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

高速マウスホイール:

ここに画像の説明を入力してください

于 2018-08-29T10:58:01.990 に答える
1

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>
于 2017-03-06T08:41:30.593 に答える
1

Drew Marshが受け入れた回答に追加したかったのですが、他の提案された回答はそれを解決しますが、場合によっては、PreviewMouseWheel他の副作用を引き起こさずにイベントをオーバーライドして処理することはできません。つまり、ネストやポップアップのように、親の前にスクロールする優先順位を受け取る必要がある子コントロールがある場合です。ScrollViewerListBoxComboBox

私のシナリオでは、私の親コントロールはでしItemsControlた。論理スクロールをデフォルトの3ではなく、アイテムごとに1単位にしたかったのです。アタッチされた動作をいじったり、マウスホイールイベントをインターセプト/処理したりする代わりに、これを行うカスタムを実装しました。ItemsPanelVirtualizingStackPanelVirtualizingStackPanel

    public class VirtualizingScrollSingleItemAtATimeStackPanel : VirtualizingStackPanel
    {
        public override void MouseWheelDown()
        {
            PageDown();
        }

        public override void MouseWheelUp()
        {
            PageUp();
        }

        public override void PageDown()
        {
            LineDown();
        }

        public override void PageUp()
        {
            LineUp();
        }
    }

次に、xamlマークアップで通常使用するのと同じようにそのパネルを使用します。

<ItemsControl>
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <controls:VirtualizingScrollSingleItemAtATimeStackPanel />
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>
</ItemsControl>

明らかに私のシナリオは考案されており、解決策は非常に単純ですが、これにより、他の人が私が遭遇した副作用なしにスクロール動作をより適切に制御できるようになる可能性があります。

于 2021-02-11T18:10:09.780 に答える
0

これは、scrollbar1.ValueChangedの整数を確認するために行いました。

scrollbar1.Value = Math.Round(scrollbar1.Value, 0, MidpointRounding.AwayFromZero)
于 2017-04-29T19:37:13.383 に答える