0
votes

I've got a ScrollViewer which contains Canvas. There are some movable UIElements at this Canvas. Here is my XAML code:

<ScrollViewer x:Name="Scroller" HorizontalScrollBarVisibility="Auto" Background="White">
       <Canvas x:Name="MapCanvas" Width="4000" Height="4000">    
                    <Button x:Name="TestBtn" 
                            Content="My button"
                            Canvas.Left="250"
                            ManipulationStarted="MapItem_ManipulationStarted"   
                            ManipulationDelta="MapItem_ManipulationDelta" 
                            ManipulationCompleted="MapItem_ManipulationCompleted"   
                            />                                  
      </Canvas>
</ScrollViewer>

Here is the code of event handlers:

private void MapItem_ManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
        {
            FrameworkElement btn = sender as FrameworkElement;
            if (null == btn) return;            

            double left = Canvas.GetLeft(btn) + e.DeltaManipulation.Translation.X;
            double top = Canvas.GetTop(btn) + e.DeltaManipulation.Translation.Y;

            if (left < 0)
                left = 0;
            else if (left >  MapCanvas.ActualWidth - btn.ActualWidth)
                left = MapCanvas.ActualWidth - btn.ActualWidth;

            if (top < 0)
                top = 0;
            else if(top > MapCanvas.ActualHeight - btn.ActualHeight)
                top = MapCanvas.ActualHeight - btn.ActualHeight;

            Canvas.SetLeft(btn, left);
            Canvas.SetTop(btn, top);

            e.Handled = true;
        }

        private void MapItem_ManipulationCompleted(object sender, System.Windows.Input.ManipulationCompletedEventArgs e)
        {
            Scroller.HorizontalScrollBarVisibility = ScrollBarVisibility.Auto;
            Scroller.VerticalScrollBarVisibility = ScrollBarVisibility.Auto;            

            e.Handled = true;
        }

        private void MapItem_ManipulationStarted(object sender, System.Windows.Input.ManipulationStartedEventArgs e)
        {
            Scroller.HorizontalScrollBarVisibility = ScrollBarVisibility.Disabled;
            Scroller.VerticalScrollBarVisibility = ScrollBarVisibility.Disabled;

            e.Handled = true;
        }

Everything works perfect. But when ScrollViewer has scrolled to some HorizontalOffset or VerticalOffset and I'm clicking or tapping any UIElement in visible area it seems like ScrollViewer automatically scrolls to HorisontalOffset == 0 and VerticalOffset == 0. Then, after releasing UIElement, it jumps back. How can I avoid this behavior and make ScrollViewer stay at it's place while I'll dragging UIElement placed into Canvas inside it?

2

2 Answers

0
votes

I haven't tested this, but you could try replacing (or adding to) your calls to disable/re-enable the scrollbar visibility with calls to disable/re-enable the ScrollViewer control itself:

private void MapItem_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
{
    Scroller.IsEnabled = false;
}

private void MapItem_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
{
    Scroller.IsEnabled = true;
}

If it does work, it may affect the Style when it becomes disabled, so you may have to re-style it using a Trigger on the IsEnabled property when it equals False.

0
votes

I found out that I needed to set ScrollViewer.ManipulationMode = ManipulationMode.Control at my page constructor and do not set HorisontalScrollBarVisibility and VerticalScrollVarVisibility (it resets offsets to 0,0 coordinates) Now it works.

Thanks!