I'm back. Here I'll explain the solution that I made to WPF now to Xamarin.Forms. First, no implement MVVM pattern easly I used nuget package Prism.Forms from Brian Lagunas. I made the ViewModel class in C# and the View code using XAML in a similar way that in the WPF Project:
This is the ViewModel code:
using Esri.ArcGISRuntime.Geometry;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Symbology;
using Esri.ArcGISRuntime.UI;
using Prism.Commands;
using Prism.Mvvm;
using System.Windows.Input;
#if WINDOWS_UWP
using Colors = Windows.UI.Colors;
#else
using Colors = System.Drawing.Color;
#endif
namespace GeonetPost.Xamarin.ViewModels
{
public class MapPageViewModel : BindableBase
{
private Map _myMap;
public Map MyMap
{
get { return _myMap; }
set { SetProperty(ref _myMap, value); }
}
private GraphicsOverlayCollection _grapchicsOverlays;
public GraphicsOverlayCollection GraphicsOverlays
{
get { return _grapchicsOverlays; }
set { SetProperty(ref _grapchicsOverlays, value); }
}
private Viewpoint _viewpoint;
public Viewpoint Viewpoint
{
get { return _viewpoint; }
set { SetProperty(ref _viewpoint, value); }
}
private Viewpoint _updatedViewpoint;
public Viewpoint UpdatedViewpoint
{
get { return _updatedViewpoint; }
set { SetProperty(ref _updatedViewpoint, value); }
}
public ICommand ButtonClickCommand { get; private set; }
public ICommand ZoomCommand { get; private set; }
public ICommand UpdateViewpointCommand { get; private set; }
public MapPageViewModel()
{
MyMap = new Map(Basemap.CreateStreets());
GraphicsOverlays = new GraphicsOverlayCollection();
ButtonClickCommand = new DelegateCommand(ButtonClickAction);
ZoomCommand = new DelegateCommand(ZoomAction);
UpdateViewpointCommand = new DelegateCommand<Viewpoint>(UpdateViewpointAction);
GraphicsOverlay go = new GraphicsOverlay()
{
Id = "MyGraphicOverlay"
};
GraphicsOverlays.Add(go);
}
private void ButtonClickAction()
{
var g = new Graphic()
{
Geometry = new MapPoint(-74, 4, SpatialReferences.Wgs84),
Symbol = new SimpleMarkerSymbol() { Color = Colors.Green, Style = SimpleMarkerSymbolStyle.Circle, Size = 10 }
};
GraphicsOverlays[0].Graphics.Clear();
GraphicsOverlays[0].Graphics.Add(g);
}
private void ZoomAction()
{
Viewpoint = new Viewpoint(4, -74, 5000000);
}
private void UpdateViewpointAction(Viewpoint vp)
{
var projectedVp = new Viewpoint(GeometryEngine.Project(vp.TargetGeometry, SpatialReferences.Wgs84), vp.Camera);
if (UpdatedViewpoint == null || projectedVp.ToJson() != UpdatedViewpoint.ToJson())
{
UpdatedViewpoint = projectedVp;
}
}
}
}
This is the View code:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
xmlns:bh="clr-namespace:GeonetPost.Xamarin.Behaviors"
xmlns:cv="clr-namespace:GeonetPost.Xamarin.Converters"
xmlns:esri="clr-namespace:Esri.ArcGISRuntime.Xamarin.Forms;assembly=Esri.ArcGISRuntime.Xamarin.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="GeonetPost.Xamarin.Views.MapPage">
<ContentPage.Resources>
<ResourceDictionary>
<cv:GeographicCoordinateConverter x:Key="GeoCoorConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<esri:MapView Map="{Binding MyMap}"
GraphicsOverlays="{Binding GraphicsOverlays}">
<esri:MapView.Behaviors>
<bh:SetMapViewViewportBehavior Viewpoint="{Binding Viewpoint}" />
<bh:MapViewViewpointChangedBehavior Command="{Binding UpdateViewpointCommand}" />
</esri:MapView.Behaviors>
</esri:MapView>
<Grid Margin="10"
HorizontalOptions="Start"
VerticalOptions="Start"
BackgroundColor="Beige">
<StackLayout Orientation="Vertical"
Margin="10"
HeightRequest="100">
<Label Text="{Binding UpdatedViewpoint.TargetGeometry.XMin, Converter={StaticResource GeoCoorConverter}, ConverterParameter='X', StringFormat='XMin = {0}'}" />
<Label Text="{Binding UpdatedViewpoint.TargetGeometry.YMin, Converter={StaticResource GeoCoorConverter}, ConverterParameter='Y', StringFormat='YMin = {0}'}" />
<Label Text="{Binding UpdatedViewpoint.TargetGeometry.XMax, Converter={StaticResource GeoCoorConverter}, ConverterParameter='X', StringFormat='XMax = {0}'}" />
<Label Text="{Binding UpdatedViewpoint.TargetGeometry.YMax, Converter={StaticResource GeoCoorConverter}, ConverterParameter='Y', StringFormat='YMax = {0}'}" />
</StackLayout>
</Grid>
<StackLayout Grid.Row="1"
Orientation="Horizontal">
<Button Margin="5"
Text="Click me!"
WidthRequest="150"
BackgroundColor="Black"
TextColor="White"
Command="{Binding ButtonClickCommand}" />
<Button Margin="5"
Text="Zoom to Point"
WidthRequest="150"
BackgroundColor="Black"
TextColor="White"
Command="{Binding ZoomCommand}" />
</StackLayout>
</Grid>
</ContentPage>
And this is the code of the SetMapViewViewportBehavior:
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Xamarin.Forms;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Xamarin.Forms;
namespace GeonetPost.Xamarin.Behaviors
{
public class SetMapViewViewportBehavior : BehaviorBase<MapView>
{
public static readonly BindableProperty ViewpointProperty =
BindableProperty.Create(nameof(Viewpoint), typeof(Viewpoint), typeof(SetMapViewViewportBehavior));
public Viewpoint Viewpoint
{
get { return (Viewpoint)GetValue(ViewpointProperty); }
set { SetValue(ViewpointProperty, value); }
}
public SetMapViewViewportBehavior()
{
}
protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == nameof(this.Viewpoint))
{
SetViewpoint(this.Viewpoint);
}
}
private async void SetViewpoint(Viewpoint vp)
{
if (vp != null)
{
var actualVp = this.AssociatedObject.GetCurrentViewpoint(ViewpointType.BoundingGeometry);
if (actualVp == null || (actualVp != null && !actualVp.Equals(vp)))
{
Debug.WriteLine("SetViewpoint");
await this.AssociatedObject.SetViewpointAsync(vp);
}
}
}
}
}
Note that I had to wrote a BehaviorBase class to implement a Behavior code that in WPF already exits. Now this that the Xamarin.Forms looks like in Windows and Android:
To see the complete solution go to this github repo https://github.com/marceloctorres/GeonetPost.Xamarin
Finally, no make a zoom to your trace route, only set the Viewport property in the MapPageViewModel class with a new Viewport using your polyline extent geometry. For example:
ViewPoint = new Viewpoint(route.Extent);
And the SetMapViewViewportBehavior does the rest.
Marcelo
Marcelo César Torres