I’ve got n playing map where I use the ScrollViewer
to move around the map, and I wish to use the ViewBox
together with PinchManipulations
to zoom in and out of the map. So far I’ve done this by setting the ScrollViewer
’s Manipulation
mode to control
, however this gives me an lag when I zoom. Is there a way to get the ViewBox
and ScrollViewer
to work better together and thereby avoid the lag? The code I’ve got so far is:
ScrollViewer:
<ScrollViewer Grid.Column ="0" Width="768" Height="380" HorizontalScrollBarVisibility="Hidden">
<Viewbox Stretch="None">
<View:Map/>
</Viewbox>
</ScrollViewer>
PinchZoom:
<Grid x:Name="Map" Width="1271" Height="1381.5">
<Grid.RenderTransform>
<ScaleTransform ScaleX="{Binding Path=deltaZoom}" ScaleY="{Binding Path=deltaZoom}"/>
</Grid.RenderTransform>
<i:Interaction.Triggers>
<i:EventTrigger EventName="ManipulationStarted">
<cmd:EventToCommand Command="{Binding Path=ZoomStartedCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
<i:EventTrigger EventName="ManipulationDelta">
<cmd:EventToCommand Command="{Binding Path=ZoomDeltaCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
<i:EventTrigger EventName="ManipulationCompleted">
<cmd:EventToCommand Command="{Binding Path=ZoomCompletedCommand}" PassEventArgsToCommand="True"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</Grid>
The code where I use the pinch zoom:
public ICommand ZoomStartedCommand { get; set; }
public ICommand ZoomDeltaCommand { get; set; }
public ICommand ZoomCompletedCommand { get; set; }
private double _deltaZoom;
public double deltaZoom
{
get
{
return _deltaZoom;
}
set
{
_deltaZoom = value;
RaisePropertyChanged("deltaZoom");
}
}
public double distance;
public MainViewModel()
{
ZoomStartedCommand = new RelayCommand<ManipulationStartedEventArgs>(ZoomStart);
ZoomDeltaCommand = new RelayCommand<ManipulationDeltaEventArgs>(ZoomDelta);
ZoomCompletedCommand = new RelayCommand<ManipulationCompletedEventArgs>(ZoomCompleted);
}
public void ZoomStart(ManipulationStartedEventArgs e)
{
FrameworkElement Element = (FrameworkElement)e.OriginalSource;
var myScrollViewer = FindParentOfType<ScrollViewer>(Element) as ScrollViewer;
myScrollViewer.SetValue(ScrollViewer.ManipulationModeProperty, ManipulationMode.Control);
}
public void ZoomDelta(ManipulationDeltaEventArgs e)
{
if (e.PinchManipulation != null)
{
deltaZoom = deltaZoom * e.PinchManipulation.DeltaScale;
}
else
{
FrameworkElement Element = (FrameworkElement)e.OriginalSource;
var myScrollViewer = FindParentOfType<ScrollViewer>(Element) as ScrollViewer;
myScrollViewer.SetValue(ScrollViewer.ManipulationModeProperty, ManipulationMode.System);
}
}
public void ZoomCompleted(ManipulationCompletedEventArgs e)
{
FrameworkElement Element = (FrameworkElement)e.OriginalSource;
var myScrollViewer = FindParentOfType<ScrollViewer>(Element) as ScrollViewer;
myScrollViewer.SetValue(ScrollViewer.ManipulationModeProperty, ManipulationMode.System);
}
I had this problem too when I tried to handle a lot of data in a single container. You can not simply load the entire map in a viewbox and use a scroll viewer and expect that everything would work fine.
The first solution to make an application to perform well on big data sets is to try UI Virtualization. A control that accepts virtualization creates only the elements needed to display the current view, or more exactly , just the elements which are visible on the display. In order to understand better this concept I will give you a real world example. Take a look at how Facebook renders its News feed. It loads X posts in the X html elements and then when the users scrolls down, it unloads non visible ones and loads the new ones.
It simply reuses elements. This is the concept of UI virtualization. I have to mention one important features: deferred scrolling (the user can scroll but the results are only displayed after the release of the click, this is a performance improvement if the user like to play up and down with the scrollbar)
Coming back to your problem. If the map is entirely loaded it is a performance issue to scroll or zoom into because the non visible parts would zoom and scroll also. Imagine what would had happened if Google Maps would not support UI Virtualization. When the user would try to zoom in , all Earth would zoom in(tons of GBs).
However your map should be fully loaded somewhere in the memory. If it is big, this is a problem and there it comes Data Virtualization. Instead of having all map fully loaded, it loads just the needed sections for display. If you want to have a better responsiveness you could use the concept that Google Maps uses. Load few more data into memory than it fits on the display when rendered, so the UI would not freeze(until the data is brought in memory) when you try to scroll.
You can read more :
I solved my problem using Virtualized Canvas. Sample of application using virtualized canvas: http://pavzav.blogspot.ro/2010/11/virtualized-canvas.html
You might like to take a look at Wpf Bing Maps Control
I think you should instead look at the viewportcontroller and look into the basic lens sample, where they have implemented this. The viewportcontroller, has a scrollviewer inside, and viewport.
The basics are this:
FYI, I completely forget why there is a canvas in there, but I feel like it is important. See below:
While the sample below does not do what you want to do, I based my code on the MediaViewer inside this sample and modified it: Basic Lens Sample
However it should be noted that it is for picture zoom.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With