Snap to Xamarin.Forms.Maps.Map from ViewModel
I am working on a Xamarin.Forms application using a map display page. XAML:
<maps:Map x:Name="Map"> ... </maps:Map> I know that the map can be accessed from the page code as follows:
var position = new Position(37.79762, -122.40181); Map.MoveToRegion(new MapSpan(position, 0.01, 0.01)); Map.Pins.Add(new Pin { Label = "Xamarin", Position = position }); But since this code violates the architecture of the MVVM application, I would prefer to access the Map object from my ViewModel rather than directly from the View / page, either using it directly, as in the above code, or by binding data to its properties.
Does anyone know how to do this?
I have two options that worked for me and that could help you.
You can add the
Xamarin.Forms.Maps Mapstatic property to yourViewModeland set this static property after setting the binding context while creating your view, as shown below:public MapsPage() { InitializeComponent(); BindingContext = new MapViewModel(); MapViewModel.Map = MyMap; }
This will allow you to access your map in your ViewModel.
You can transfer your map from your view to the ViewModel during the binding, for example:
<maps:Map x:Name="MyMap" IsShowingUser="true" MapType="Hybrid" /> <StackLayout Orientation="Horizontal" HorizontalOptions="Center"> <Button x:Name="HybridButton" Command="{Binding MapToHybridViewChangeCommand}" CommandParameter="{x:Reference MyMap}" Text="Hybrid" HorizontalOptions="Center" VerticalOptions="Center" Margin="5"/>`
And get the map behind from the ViewModel team.
I donβt think Pins is a binding property on Map , you might want to write a function request on Xamarin Uservoice or four here: http://forums.xamarin.com/discussion/31273/
This is not ideal, but you can listen to the event with the changed property in the code behind, and then apply the change from there. Its a little tame, but it's doable.
((ViewModels.YourViewModel)BindingContext).PropertyChanged += yourPropertyChanged; And then define the method "yourPropertyChanged"
private void yourPropertyChanged(object sender, PropertyChangedEventArgs e) { if(e.PropertyName == "YourPropertyName") { var position = new Position(37.79762, -122.40181); Map.MoveToRegion(new MapSpan(position, 0.01, 0.01)); Map.Pins.Add(new Pin { Label = "Xamarin", Position = position }); } } If you don't want to break the MVVM template and still be able to access your Map object from the ViewModel, you can open the Map instance using the property from the ViewModel and associate it with your view.
Your code should be structured as described below.
ViewModel:
using Xamarin.Forms.Maps; namespace YourApp.ViewModels { public class MapViewModel { public MapViewModel() { Map = new Map(); } public Map Map { get; private set; } } } View (in this example I am using ContentPage , but you can use whatever you want):
<?xml version="1.0" encoding="utf-8" ?> <ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="YourApp.Views.MapView"> <ContentPage.Content> <!--The map--> <ContentView Content="{Binding Map}"/> </ContentPage.Content> </ContentPage> I have not shown how, but the above code can be used only if the ViewModel is the BindingContext your view.