Grab-to-pan in Silverlight app

匆匆过客 提交于 2019-12-19 04:08:28

问题


I have a Canvas inside a ScrollViewer. I want to have the user to be able to grab the canvas and move it around, with the thumbs on the scrollbars updating appropriately.
My initial implementation calculates the offset on each mouse move, and updates the scrollbars:

 // Calculate the new drag distance
 Point newOffsetPos = e.GetPosition(MapCanvas);
 System.Diagnostics.Debug.WriteLine("   newOffsetPos : " + newOffsetPos.X + " " + newOffsetPos.Y);

 double deltaX = newOffsetPos.X - _offsetPosition.X ;
 double deltaY = newOffsetPos.Y - _offsetPosition.Y ;

 System.Diagnostics.Debug.WriteLine("   delta X / Y : " + deltaX + " " + deltaY);
 System.Diagnostics.Debug.WriteLine("   sv offsets X / Y : " + _scrollViewer.HorizontalOffset + " " + _scrollViewer.VerticalOffset);

 _scrollViewer.ScrollToHorizontalOffset(_scrollViewer.HorizontalOffset - deltaX);
 _scrollViewer.ScrollToVerticalOffset(_scrollViewer.VerticalOffset - deltaY);

 _offsetPosition = newOffsetPos;

While this works, it is not very smooth.
Is there a better way to do this? If Transforms are used, will the scrollbars update automagically when the Canvas is moved?
Thanks for any tips...


回答1:


Actually this sort of problem is really a matter of using the right pattern to track the mouse. I've seen this issue in variety of cases not just in Silverlight.

The best pattern is to trap the original locations of both mouse and subject, then recalculate the new offset from the fixed original values. That way the mouse stays planted solid at a single point on the image being panned. Here is my simple Repro:-

Start with a fresh Silverlight Application in visual studio. Modify MainPage.Xaml thus:-

<UserControl x:Class="SilverlightApplication1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid x:Name="LayoutRoot" Background="White">
        <ScrollViewer x:Name="Scroller" HorizontalScrollBarVisibility="Auto">
            <Image x:Name="Map" Source="test.jpg" Width="1600" Height="1200" />
        </ScrollViewer>
    </Grid>
</UserControl>

Add the following code to the MainPage.xaml.cs file:-

    public MainPage()
    {
        InitializeComponent();
        Map.MouseLeftButtonDown += new MouseButtonEventHandler(Map_MouseLeftButtonDown);
    }

    void Map_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        Point mapOrigin = new Point(Scroller.HorizontalOffset, Scroller.VerticalOffset);
        Point mouseOrigin = e.GetPosition(Application.Current.RootVisual);

        MouseEventHandler moveHandler = null;
        MouseButtonEventHandler upHandler = null;

        moveHandler = (s, args) =>
        {
            Point mouseNew = args.GetPosition(Application.Current.RootVisual);
            Scroller.ScrollToHorizontalOffset(mapOrigin.X - (mouseNew.X - mouseOrigin.X));
            Scroller.ScrollToVerticalOffset(mapOrigin.Y - (mouseNew.Y - mouseOrigin.Y));
        };


        upHandler = (s, args) =>
        {
            Scroller.MouseMove -= moveHandler;
            Scroller.MouseLeftButtonUp -= upHandler;
        };

        Scroller.MouseMove += moveHandler;
        Scroller.MouseLeftButtonUp += upHandler;
    }
}

Give it a reasonably large test.jpg (doesn't need to be 1600x1200 Image will scale it).

You'll note that when dragging the mouse remains exactly over a fixed point in the image until you hit a boundary. Move the mouse as fast as you like it always tracks, this is because it doesn't depend on deltas being accurate and up-to-date. The only variable is the current mouse position, the other values remain fixed as they were at mouse down.




回答2:


You could try this (or at least take a peek at how it's implemented).



来源:https://stackoverflow.com/questions/2179286/grab-to-pan-in-silverlight-app

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!