'in WPF. How to scroll Objects in ScrollViewer by mouse-dragging, like as iPhone?

it's done well to scroll by mouse-wheel or scrollbar seed-dragging. but scrolling by mouse-dragging contents on scroll view is not done. How can i implement this action?

        <ScrollViewer x:Name="scrollViewer" Grid.Row="1" HorizontalScrollBarVisibility="Auto" CanContentScroll="True">
            <Grid x:Name="galleryGrid" ShowGridLines="True">
                <Grid.RowDefinitions>
                    <RowDefinition Height="*"></RowDefinition>
                    <RowDefinition Height="*"></RowDefinition>
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="500"></ColumnDefinition>
                    <ColumnDefinition Width="500"></ColumnDefinition>
                    <ColumnDefinition Width="500"></ColumnDefinition>
                    <ColumnDefinition Width="500"></ColumnDefinition>
                    <ColumnDefinition Width="500"></ColumnDefinition>
                </Grid.ColumnDefinitions>
                <Button Grid.Column="0" Magin="10,10,10,10">Test</Button>
                <Button Grid.Column="1" Magin="10,10,10,10">Test</Button>
                <Button Grid.Column="2" Magin="10,10,10,10">Test</Button>
                <Button Grid.Column="3" Magin="10,10,10,10">Test</Button>
                <Button Grid.Column="4" Magin="10,10,10,10">Test</Button>
            </Grid>
        </ScrollViewer>


Solution 1:[1]

I found a way of resolving this. It's following...

    Point scrollMousePoint = new Point();
    double hOff = 1;
    private void scrollViewer_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        scrollMousePoint = e.GetPosition(scrollViewer);
        hOff = scrollViewer.HorizontalOffset;
        scrollViewer.CaptureMouse();
    }

    private void scrollViewer_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        if(scrollViewer.IsMouseCaptured)
        {
            scrollViewer.ScrollToHorizontalOffset(hOff + (scrollMousePoint.X - e.GetPosition(scrollViewer).X));
        }
    }

    private void scrollViewer_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        scrollViewer.ReleaseMouseCapture();
    }

    private void scrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
    {
        scrollViewer.ScrollToHorizontalOffset(scrollViewer.HorizontalOffset + e.Delta);
    }

thanks!

Solution 2:[2]

I did this class to scroll while keeping the scrollviewer buttons. From the code from user110777, but this works with vertical instead of horizontally, and works well with the viewer (Since I'm now only capturing the content). Plus I'm using MouseLeftButtonDown instead of the preview in order to allow the user to click things like the combobox without causing a drag. (If you want label or Textblock to drag set their IsHitTestVisible=false)

public class ScrollDragger
{
    private readonly ScrollViewer _scrollViewer;
    private readonly UIElement _content;
    private Point _scrollMousePoint;
    private double _hOff = 1;

    public ScrollDragger(UIElement content, ScrollViewer scrollViewer)
    {
        _scrollViewer = scrollViewer;
        _content = content;
        content.MouseLeftButtonDown += scrollViewer_MouseLeftButtonDown;
        content.PreviewMouseMove += scrollViewer_PreviewMouseMove;
        content.PreviewMouseLeftButtonUp += scrollViewer_PreviewMouseLeftButtonUp;
    }

    private void scrollViewer_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        _content.CaptureMouse();
        _scrollMousePoint = e.GetPosition(_scrollViewer);
        _hOff = _scrollViewer.VerticalOffset;
    }

    private void scrollViewer_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        if (_content.IsMouseCaptured)
        {
            var newOffset = _hOff + (_scrollMousePoint.Y - e.GetPosition(_scrollViewer).Y);
            _scrollViewer.ScrollToVerticalOffset(newOffset);
        }
    }

    private void scrollViewer_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        _content.ReleaseMouseCapture();
    } 
}

Solution 3:[3]

This is how I did it, XAML:

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="20px"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0" Text="this is not in the scrollviewer" Name="tb"/>
    <ScrollViewer Name="sv" 
                  HorizontalScrollBarVisibility="Auto" 
                  Grid.Row="1">
        <StackPanel Name="sp" Width="500" Height="500"
                    MouseMove="sp_MouseMove" 
                    Background="Transparent">
            <Ellipse Height="50" Width="50" Fill="Green"/>
        </StackPanel>

    </ScrollViewer>
</Grid>

C#:

private void sp_MouseMove(object sender, MouseEventArgs e)
    {
        Point newMousePosition = Mouse.GetPosition((StackPanel)sender);
        tb.Text = newMousePosition.X + " | " + newMousePosition.Y;

        if (Mouse.LeftButton == MouseButtonState.Pressed)
        {
            if (newMousePosition.Y < oldMousePosition.Y)
                sv.ScrollToVerticalOffset(sv.VerticalOffset + 1);
            if (newMousePosition.Y > oldMousePosition.Y)
                sv.ScrollToVerticalOffset(sv.VerticalOffset - 1);

            if (newMousePosition.X < oldMousePosition.X)
                sv.ScrollToHorizontalOffset(sv.HorizontalOffset + 1);
            if (newMousePosition.X > oldMousePosition.X)
                sv.ScrollToHorizontalOffset(sv.HorizontalOffset - 1);
        }
        else
        {
            oldMousePosition = newMousePosition;
        }
    }

where Point oldMousePosition; is a member of the window.

Solution 4:[4]

UWP variation:

    Pointer pointer;
    PointerPoint scrollMousePoint ;
    double hOff = 1;

    private void MainScrollviewer_PointerPressed(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
    {
        pointer = e.Pointer;
        scrollMousePoint = e.GetCurrentPoint(scrollviewer);
        hOff = scrollviewer.HorizontalOffset;
        scrollviewer.CapturePointer(pointer);
    }

    private void MainScrollviewer_PointerReleased(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
    {
        scrollviewer.ReleasePointerCaptures();
    }

    private void MainScrollviewer_PointerMoved(object sender, Windows.UI.Xaml.Input.PointerRoutedEventArgs e)
    {
        if (scrollviewer.PointerCaptures!= null&& scrollviewer.PointerCaptures.Count>0)
        {
          scrollviewer.ChangeView(hOff + (scrollMousePoint.Position.X - e.GetCurrentPoint(scrollviewer).Position.X),null,null);
        }
    }

I know that question was for WPF, but this was best result I found searching for UWP solution.

Solution 5:[5]

use this

for horizontal scrolling

private void ScrollViewer_OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)     
{             
    ScrollViewer scv = (ScrollViewer)sender;               
    scv.ScrollToHorizontalOffset(scv.HorizontalOffset - e.Delta);
    e.Handled = true;    
}

Solution 6:[6]

You can do this in C# WPF like this. note that there are two type of Point classes.From them you should use System.Windows.Point to get this work.These are mouse related events for your ScrollViewer.The code below will scroll your object to both horizontal and vertical inside the ScrollViewer.

   System.Windows.Point ScrollMousePoint1 = new System.Windows.Point();
   double HorizontalOff1 = 1; double VerticalOff1 = 1;
   private void ScrollViewer1_PreviewMouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            ScrollMousePoint1 = e.GetPosition(ScrollViewer1);
            HorizontalOff1 = ScrollViewer1.HorizontalOffset;
            VerticalOff1 = ScrollViewer1.VerticalOffset;
            ScrollViewer1.CaptureMouse();
        }

        private void ScrollViewer1_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            if (ScrollViewer1.IsMouseCaptured)
            {
                ScrollViewer1.ScrollToHorizontalOffset(HorizontalOff1 + (ScrollMousePoint1.X - e.GetPosition(ScrollViewer1).X));
                ScrollViewer1.ScrollToVerticalOffset(VerticalOff1 + (ScrollMousePoint1.Y - e.GetPosition(ScrollViewer1).Y));
            }
        }

        private void ScrollViewer1_PreviewMouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            ScrollViewer1.ReleaseMouseCapture();
        }

        private void ScrollViewer1_PreviewMouseWheel(object sender, System.Windows.Input.MouseWheelEventArgs e)
        {
            ScrollViewer1.ScrollToHorizontalOffset(ScrollViewer1.HorizontalOffset + e.Delta);
            ScrollViewer1.ScrollToVerticalOffset(ScrollViewer1.VerticalOffset + e.Delta);
        }

Solution 7:[7]

My experience: follow user110777 Changed below code

private void scrollViewer_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
       scrollMousePoint = e.GetPosition(scrollViewer);
        hOff = scrollViewer.HorizontalOffset;
        scrollViewer.CaptureMouse();
    }

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Sago
Solution 2 AL - Divine
Solution 3 John Laszlo
Solution 4 MadMaxIV
Solution 5 gleng
Solution 6 naseer mohammad
Solution 7 Glorfindel