none
マウス操作でタッチと同じようにスクロールしたい RRS feed

  • 質問

  • <ScrollViewer PanningMode="VerticalFirst" >
        <WrapPanel Name="Lst">

        </WrapPanel>
    </ScrollViewer>

    上記のようなコードの場合、タッチであれば、リストボックス内のどこから上下にスライドしても

    慣性スクロールされますが、マウスの場合スクロールバーを上下させるかマウスホイールによる

    操作となります。

    これをタッチと同じように慣性スクロールさせたいのですが、方法はあるのでしょうか?

    2012年10月21日 9:05

回答

  • MouseMoveをハンドルして処理する必要がありますね。
    とりあえずドラッグ量だけ移動させる場合のコードを書いてみました。

            Point _startPoint;
            Point _startPosition;
    
            private void ScrollViewer_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                _startPoint = e.GetPosition((ScrollViewer)sender);
                
                ScrollViewer scrollViewer = (ScrollViewer)sender;
                _startPosition = new Point(scrollViewer.HorizontalOffset, scrollViewer.VerticalOffset);
            }
    
            private void ScrollViewer_MouseMove(object sender, MouseEventArgs e)
            {
                if (e.LeftButton == MouseButtonState.Pressed)
                {
                    ScrollViewer scrollViewer = (ScrollViewer)sender;
                    Point point = e.GetPosition((ScrollViewer)sender);
                    if (scrollViewer.PanningMode == PanningMode.VerticalFirst | scrollViewer.PanningMode == PanningMode.VerticalOnly)
                    {
                        scrollViewer.ScrollToVerticalOffset(_startPosition.Y + (point.Y - _startPoint.Y) * -1);
                    }
                    else if (scrollViewer.PanningMode == PanningMode.HorizontalFirst | scrollViewer.PanningMode == PanningMode.HorizontalOnly)
                    {
                        scrollViewer.ScrollToVerticalOffset(_startPosition.X + (point.X - _startPoint.X) * -1);
                    }
                }
            }

    PreviewMouseLeftButtonDownでポイント開始時の位置とスクロールバーの位置を記憶し、MouseMoveでポイント開始位置との差分だけスクロールバーを動かしています。
    加速度の処理をやろうと思うと移動量の他に移動時間も取って、慣性移動量の計算をしないといけないので、それはご自分で頑張ってください(笑)

    以上、参考になれば幸いです。

    • 回答としてマーク QuarterDeck 2012年10月23日 7:06
    • 回答としてマークされていない QuarterDeck 2012年10月23日 7:06
    • 回答としてマーク QuarterDeck 2012年10月23日 7:09
    2012年10月21日 11:06

すべての返信

  • MouseMoveをハンドルして処理する必要がありますね。
    とりあえずドラッグ量だけ移動させる場合のコードを書いてみました。

            Point _startPoint;
            Point _startPosition;
    
            private void ScrollViewer_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
            {
                _startPoint = e.GetPosition((ScrollViewer)sender);
                
                ScrollViewer scrollViewer = (ScrollViewer)sender;
                _startPosition = new Point(scrollViewer.HorizontalOffset, scrollViewer.VerticalOffset);
            }
    
            private void ScrollViewer_MouseMove(object sender, MouseEventArgs e)
            {
                if (e.LeftButton == MouseButtonState.Pressed)
                {
                    ScrollViewer scrollViewer = (ScrollViewer)sender;
                    Point point = e.GetPosition((ScrollViewer)sender);
                    if (scrollViewer.PanningMode == PanningMode.VerticalFirst | scrollViewer.PanningMode == PanningMode.VerticalOnly)
                    {
                        scrollViewer.ScrollToVerticalOffset(_startPosition.Y + (point.Y - _startPoint.Y) * -1);
                    }
                    else if (scrollViewer.PanningMode == PanningMode.HorizontalFirst | scrollViewer.PanningMode == PanningMode.HorizontalOnly)
                    {
                        scrollViewer.ScrollToVerticalOffset(_startPosition.X + (point.X - _startPoint.X) * -1);
                    }
                }
            }

    PreviewMouseLeftButtonDownでポイント開始時の位置とスクロールバーの位置を記憶し、MouseMoveでポイント開始位置との差分だけスクロールバーを動かしています。
    加速度の処理をやろうと思うと移動量の他に移動時間も取って、慣性移動量の計算をしないといけないので、それはご自分で頑張ってください(笑)

    以上、参考になれば幸いです。

    • 回答としてマーク QuarterDeck 2012年10月23日 7:06
    • 回答としてマークされていない QuarterDeck 2012年10月23日 7:06
    • 回答としてマーク QuarterDeck 2012年10月23日 7:09
    2012年10月21日 11:06
  • 慣性以外のアニメーションも付加されてしまいますが(例えばリストアイテムを削除する際にアニメーションが入る)、FluidMoveBehaviorを使うと慣性スクロールするようになります。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    2012年10月22日 1:20
    モデレータ
  • ありがとうございます。無事に目的の事が出来ました。

    ScrollViewerのMouseMoveを使うことに頭が行きませんでした。

    一生懸命WrapPanelのMouseuMoveをいじっていた自分が恥ずかしいです。

    2012年10月23日 7:08
  • 初めて知ったFluidMoveBehaviorですが、勉強して使いこなせるようにします。

    別のサイトでサンプル見たのですがすごいことが出来そうですね。

    2012年10月23日 7:09
  • 初めて知ったFluidMoveBehaviorですが、勉強して使いこなせるようにします。

    環境がわからないのですが、意外に簡単に設定できますよ。

    Windowタグに以下の2行を追加し、

    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
    xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"

    Window.Resourcesタグに、例えば以下を追加し、

    <Window.Resources>
        <ItemsPanelTemplate x:Key="ItemsPanelTemplate1">
            <StackPanel>
                <i:Interaction.Behaviors>
                    <ei:FluidMoveBehavior AppliesTo="Children" Duration="0:0:0.5">
                        <ei:FluidMoveBehavior.EaseY>
                            <QuadraticEase EasingMode="EaseOut"/>
                        </ei:FluidMoveBehavior.EaseY>
                    </ei:FluidMoveBehavior>
                </i:Interaction.Behaviors>
            </StackPanel>
        </ItemsPanelTemplate>
    </Window.Resources>

    ListBoxに以下を追加するだけです。

     ItemsPanel="{StaticResource ItemsPanelTemplate1}"

    ListBoxを削除した時に、ぬるっとアニメーションで削除されるのが面白いですよ。


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/

    2012年10月23日 8:29
    モデレータ
  • ソースを元に組み込んだところ、コンテンツをマウスで上下させることは出来るようになったのですが、スクロールバーを上下させると

    画面がちらつく現象が現れるようになりました。

    恐らく、MouseMoveの処理と本来のスクロールバーの処理がかぶってしまっているみたいなので、

    以下のようにソースを変更して動くようにしました。

    Private _startPoint As Point
        Private _startPosition As Point
        Private NotAction As Boolean = False
        Private Sub ScrollViewer_PreviewMouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs) Handles Scl.PreviewMouseLeftButtonDown
            _startPoint = e.GetPosition(DirectCast(sender, ScrollViewer))
            Dim scrollViewer As ScrollViewer = DirectCast(sender, ScrollViewer)
            _startPosition = New Point(scrollViewer.HorizontalOffset, scrollViewer.VerticalOffset)
    
            '30は暫定値 実際はスクロールバーのサイズ
            If _startPoint.X > scrollViewer.ActualWidth - 30 Then
                NotAction = True
            Else
                NotAction = False
            End If
        End Sub
        Private Sub ScrollViewer_MouseMove(sender As Object, e As MouseEventArgs) Handles Scl.MouseMove
            If NotAction = True Then Exit Sub
            If e.LeftButton = MouseButtonState.Pressed Then
                Dim scrollViewer As ScrollViewer = DirectCast(sender, ScrollViewer)
                Dim point As Point = e.GetPosition(DirectCast(sender, ScrollViewer))
                If scrollViewer.PanningMode = PanningMode.VerticalFirst Or scrollViewer.PanningMode = PanningMode.VerticalOnly Then
                    scrollViewer.ScrollToVerticalOffset(_startPosition.Y + (point.Y - _startPoint.Y) * -1)
                ElseIf scrollViewer.PanningMode = PanningMode.HorizontalFirst Or scrollViewer.PanningMode = PanningMode.HorizontalOnly Then
                    scrollViewer.ScrollToVerticalOffset(_startPosition.X + (point.X - _startPoint.X) * -1)
                End If
            End If
        End Sub

    とりあえずは、縦スクロール対応版ですが、ScrollViewerコントロールのスクロールバー部分のWidthもしくは、Heightを取得する方法はあるのでしょうか?

    2012年10月24日 6:04