how to get MapView in ViewModel Using MVVM

13095
16
Jump to solution
05-31-2017 04:07 AM
NadirHussain
Occasional Contributor II

Dear All,

i am using mvvm technique.my model class is given below.

<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="auto" />
</Grid.RowDefinitions>
<Grid Grid.Row="0" RowSpacing="0" ColumnSpacing="0" BackgroundColor="Transparent">
<esriUI:MapView x:Name="MyMapView" Map="{Binding myMap}" BackgroundColor="GreenYellow" />
</Grid>
<Grid Grid.Row="1" RowSpacing="0" ColumnSpacing="0" BackgroundColor="Transparent">
    <Button Text="Direction" BackgroundColor="Black" TextColor="White" Command="{Binding Hello}" />
</Grid>
</Grid>

On my button click i want to ACCESS MyMapView in my model in modelview class.I cant under stand how i get the reference of this MyMapView  on event in modelview.because on click event i want to add some graphics on my map.

please help.Thanks in advance.

please help.

Thanks in advance

0 Kudos
16 Replies
NadirHussain
Occasional Contributor II

Dear Marcelo,

Actually i want to calculate the distance from start to end point.and draw route.When draw route it should zoom to that route.i cant zoom to that path.

Thanks in advance.I am waiting for the sample code.

 

0 Kudos
NagmaYasmin
Occasional Contributor III

Hi Nadir,

I assumed you already created the route and would like to zoom to the extent of that route. Below is the code that zooms to that extent:

 await MyMapView.SetViewpointAsync(new Viewpoint(route.Extent));

Hope that helps.

Nagma

0 Kudos
marceloctorres
Esri Contributor

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;

    /// <summary>
    /// 
    /// </summary>
    public Map MyMap
    {
      get { return _myMap; }
      set { SetProperty(ref _myMap, value); }
    }

    private GraphicsOverlayCollection _grapchicsOverlays;

    /// <summary>
    /// 
    /// </summary>
    public GraphicsOverlayCollection GraphicsOverlays
    {
      get { return _grapchicsOverlays; }
      set { SetProperty(ref _grapchicsOverlays, value); }
    }

    private Viewpoint _viewpoint;

    /// <summary>
    /// 
    /// </summary>
    public Viewpoint Viewpoint
    {
      get { return _viewpoint; }
      set { SetProperty(ref _viewpoint, value); }
    }

    private Viewpoint _updatedViewpoint;

    /// <summary>
    /// 
    /// </summary>
    public Viewpoint UpdatedViewpoint
    {
      get { return _updatedViewpoint; }
      set { SetProperty(ref _updatedViewpoint, value); }
    }

    /// <summary>
    /// 
    /// </summary>
    public ICommand ButtonClickCommand { get; private set; }

    /// <summary>
    /// 
    /// </summary>
    public ICommand ZoomCommand { get; private set; }

    /// <summary>
    /// 
    /// </summary>
    public ICommand UpdateViewpointCommand { get; private set; }


    /// <summary>
    /// 
    /// </summary>
    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);
    }

    /// <summary>
    /// 
    /// </summary>
    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);
    }

    /// <summary>
    /// 
    /// </summary>
    private void ZoomAction()
    {
      Viewpoint = new Viewpoint(4, -74, 5000000);
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="vp"></param>
    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>
  {
    /// <summary>
    /// 
    /// </summary>
    public static readonly BindableProperty ViewpointProperty =
      BindableProperty.Create(nameof(Viewpoint), typeof(Viewpoint), typeof(SetMapViewViewportBehavior));

    /// <summary>
    /// 
    /// </summary>
    public Viewpoint Viewpoint
    {
      get { return (Viewpoint)GetValue(ViewpointProperty); }
      set { SetValue(ViewpointProperty, value); }
    }

    /// <summary>
    /// 
    /// </summary>
    public SetMapViewViewportBehavior()
    {
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="propertyName"></param>
    protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
      base.OnPropertyChanged(propertyName);
      if (propertyName == nameof(this.Viewpoint))
      {
        SetViewpoint(this.Viewpoint);
      }
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="vp"></param>
    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:

UWP App

Android App

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
NadirHussain
Occasional Contributor II

Dear Marcelo,

 I implement the code like you suggest.Its working great.I am facing other issue.I want to implement the mapview GeoViewTapped event.how to apply this in MVVM. 

waiting for reply.

Thanks for your kind cooperation.

0 Kudos
NadirHussain
Occasional Contributor II

Dear Marcelo,

 I implement the code below for GeoViewTapped event.Behaviour class for tabbed event.

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Input;
using Esri.ArcGISRuntime.Xamarin.Forms;
using Xamarin.Forms;
using System.Diagnostics;
using Esri.ArcGISRuntime.Geometry;

namespace MasterDetail.Behaviors
{
class ClsCustomBehviour : BehaviorBase<MapView>
{
public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(ClsCustomBehviour));

public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set
{
SetValue(CommandProperty, value);
}
}

protected override void OnAttachedTo(MapView bindable)
{
base.OnAttachedTo(bindable);
bindable.GeoViewTapped += this.TabbedPointAction;


}

/// <summary>
///
/// </summary>
/// <param name="bindable"></param>
protected override void OnDetachingFrom(MapView bindable)
{
base.OnDetachingFrom(bindable);
bindable.GeoViewTapped -= this.TabbedPointAction;
}

private void TabbedPointAction(object sender, Esri.ArcGISRuntime.Xamarin.Forms.GeoViewInputEventArgs e)
{
if (this.Command != null)
{
var mapClickPoint = e.Location;
if (this.Command.CanExecute(mapClickPoint))
{
this.Command.Execute(mapClickPoint);
}
}
}


}
}

////View XAML////

<esriUI:MapView Map="{Binding MyMap}"
GraphicsOverlays="{Binding GraphicsOverlays}">
<esriUI:MapView.Behaviors>
<bh:SetMapViewViewportBehavior Viewpoint="{Binding Viewpoint}" />
<bh:MapViewViewpointChangedBehavior Command="{Binding UpdateViewpointCommand}" />
<bh:ClsCustomBehviour Command="{Binding TabbedClickCommand}" />
</esriUI:MapView.Behaviors>

</esriUI:MapView>

above is my view.

///View MODEL CLASS

// TabbedClickCommand = new DelegateCommand<MapPoint>(tabbedPoint);
TabbedClickCommand = new DelegateCommand(tabbedPoint);

private void tabbedPoint()
{
Debug.WriteLine("Hello");
throw new NotImplementedException();
}

when i click on the map the code run it comes into tabbedpoint event.and print hello.But when i execute like 

TabbedClickCommand = new DelegateCommand<MapPoint>(tabbedPoint);

private void tabbedPoint(MapPoint obj)
{
throw new NotImplementedException();
}

my code not execute.i could not find the way how to execute the below function.Because i need clicked location point for further process.Please help me.how to solve.

Thanks again.

Waiting........................

0 Kudos
AnttiKajanus1
Occasional Contributor III

You can follow the same approach described in https://community.esri.com/message/520348 

NadirHussain
Occasional Contributor II

Dear Antti Kajanus

i read this.I need the sample example.so i fallow that.i try for GITHUB but link is not working.Please provide some samle example.

Thanks

0 Kudos