Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c#

wpf

xaml

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>
like image 280
user110777 Avatar asked Dec 19 '13 11:12

user110777


4 Answers

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();
    } 
}
like image 50
AL - Divine Avatar answered Nov 09 '22 07:11

AL - Divine


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!

like image 35
user110777 Avatar answered Nov 09 '22 05:11

user110777


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.

like image 29
John Laszlo Avatar answered Nov 09 '22 05:11

John Laszlo


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.

like image 31
MadMaxIV Avatar answered Nov 09 '22 06:11

MadMaxIV