I'm developing a Xamarin.Forms app with ArcGIS Runtime SDK for .NET. I don't want write code at the Code-Behind of my MapPage.xaml Form, then I wrote a Behavior to capture de ViewpointChanged event and then store the value to a property in the ViewModel class.
using Esri.ArcGISRuntime.Xamarin.Forms;
using System;
using System.Windows.Input;
using Xamarin.Forms;
namespace TrabajarMapasPortal.Behaviors
{
public class MapViewViewpointChangedBehavior : BehaviorBase<MapView>
{
/// <summary>
///
/// </summary>
public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command",
typeof(ICommand),
typeof(MapViewViewpointChangedBehavior));
/// <summary>
///
/// </summary>
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set
{
SetValue(CommandProperty, value);
}
}
/// <summary>
///
/// </summary>
protected override void OnAttachedTo(MapView bindable)
{
base.OnAttachedTo(bindable);
bindable.ViewpointChanged += this.MapViewViewpointChanged;
}
/// <summary>
///
/// </summary>
/// <param name="bindable"></param>
protected override void OnDetachingFrom(MapView bindable)
{
base.OnDetachingFrom(bindable);
bindable.ViewpointChanged -= this.MapViewViewpointChanged;
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MapViewViewpointChanged(object sender, EventArgs e)
{
if (this.Command != null)
{
MapView mapView = (MapView)sender;
if(mapView != null)
{
var viewpoint= mapView.GetCurrentViewpoint(Esri.ArcGISRuntime.Mapping.ViewpointType.BoundingGeometry);
if (this.Command.CanExecute(viewpoint))
{
this.Command.Execute(viewpoint);
}
}
}
}
}
}
Then I try to attach the behavior to the MapView in the xaml Form:
<?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:esriUI="clr-namespace:Esri.ArcGISRuntime.Xamarin.Forms;assembly=Esri.ArcGISRuntime.Xamarin.Forms"
xmlns:local="clr-namespace:TrabajarMapasPortal.Shared;assembly=TrabajarMapasPortal"
xmlns:vm="clr-namespace:TrabajarMapasPortal.ViewModels;assembly=TrabajarMapasPortal"
xmlns:prism="clr-namespace:Prism.Mvvm;assembly=Prism.Forms"
prism:ViewModelLocator.AutowireViewModel="True"
xmlns:bh="clr-namespace:TrabajarMapasPortal.Behaviors;assembly=TrabajarMapasPortal"
x:Class="TrabajarMapasPortal.Views.MapPage">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="70"/>
</Grid.RowDefinitions>
<esriUI:MapView x:Name="MapView"
Map="{Binding Path=Map}">
<esriUI:Mapview.Behaviors>
<bh:MapViewViewporChangedBehavior
Command="{Binding Path=UpdateViewpointCommand}" />
</esriUI:Mapview.Behaviors>
</esriUI:MapView>
<ListView x:Name="BasemapListBox"
ItemsSource="{Binding Path=BasemapChoices}"
Grid.Row="0"
IsVisible="{Binding Path=IsBasemapListVisible}">
<ListView.Behaviors>
<bh:ListViewItemTappedBehavior
Command="{Binding Path=ChangeBasemapCommand}"/>
</ListView.Behaviors>
<ListView.BackgroundColor>
<OnPlatform x:TypeArguments="Color"
Android="Black"
WinPhone="#6FFFFFFF" />
</ListView.BackgroundColor>
<ListView.Margin>
<OnPlatform x:TypeArguments="Thickness"
WinPhone="25" />
</ListView.Margin>
</ListView>
<Grid Grid.Row="1"
Margin="5,2">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Button x:Name="BasemapsButton"
Grid.Column="0"
Text="Mapa Base"
Command="{Binding Path=BaseMapsCommand}" />
<Button x:Name="NewMapButton"
Grid.Column="1"
Text="Nuevo"/>
<Button x:Name="SaveMapButton"
Grid.Column="2"
Text="Guardar ..."
Command="{Binding Path=ShowSaveMapPageCommand}"/>
</Grid>
</Grid>
</ContentPage>
But I get the next error message at compile time:
TrabajarMapasPortal.Views.MapPage.xaml(19,10): error : Position 19:10.
Type Mapview not found in xmlns clr-namespace:Esri.ArcGISRuntime.Xamarin.Forms;
assembly=Esri.ArcGISRuntime.Xamarin.Forms
This is the ViewModel file:
using System;
using System.Windows.Input;
using System.Threading.Tasks;
using Esri.ArcGISRuntime.Mapping;
using Esri.ArcGISRuntime.Portal;
using Esri.ArcGISRuntime.Security;
using Prism.Navigation;
using Prism.Events;
using Prism.Commands;
/// <summary>
///
/// </summary>
namespace TrabajarMapasPortal.ViewModels
{
using Events;
using Prism.Services;
/// <summary>
///
/// </summary>
public class MapPageViewModel : ViewModelBase
{
private Map _map;
private bool _isBasemapListVisible;
private const string ArcGISOnlineUrl = "https://www.arcgis.com/sharing/rest";
public const string AppClientId = "fqCCjw5dkUpIuZba";
private const string OAuthRedirectUrl = "https://developers.arcgis.com";
/// <summary>
///
/// </summary>
public Map Map
{
get { return this._map; }
set { SetProperty<Map>(ref this._map, value); }
}
/// <summary>
///
/// </summary>
private Viewpoint CurrentViewpoint { get; set; }
/// <summary>
///
/// </summary>
public bool IsMapSaved
{
get { return (this.Map != null && this.Map.Item != null); }
}
/// <summary>
///
/// </summary>
public string[] BasemapChoices { get; private set; }
/// <summary>
///
/// </summary>
public bool IsBasemapListVisible
{
get { return this._isBasemapListVisible; }
set { SetProperty<bool>(ref this._isBasemapListVisible, value); }
}
/// <summary>
///
/// </summary>
public ICommand BaseMapsCommand { get; private set; }
/// <summary>
///
/// </summary>
public ICommand ChangeBasemapCommand { get; private set; }
/// <summary>
///
/// </summary>
public ICommand ShowSaveMapPageCommand { get; private set; }
/// <summary>
///
/// </summary>
public ICommand UpdateViewpointCommand { get; private set; }
/// <summary>
///
/// </summary>
public MapPageViewModel(INavigationService navigationService, IEventAggregator eventAgreggator, IPageDialogService dialogService)
{
this.DialogService = dialogService;
this.EventAggregator = eventAgreggator;
this.NavigationService = navigationService;
this.EventAggregator
.GetEvent<SaveMapEvent>()
.Subscribe(SaveMapAction);
this.Map = new Map(Basemap.CreateStreetsVector());
this.BaseMapsCommand = new DelegateCommand(BaseMapsAction);
this.ChangeBasemapCommand = new DelegateCommand<string>(ChangeBasemapAction);
this.ShowSaveMapPageCommand = new DelegateCommand(this.ShowSaveMapPageAction);
this.UpdateViewpointCommand = new DelegateCommand<Viewpoint>(this.UpdateCurrentViewPointAction);
this.BasemapChoices = new string [] {
"Topográfico",
"Topográfico Vector",
"Calles",
"Calles Vector",
"Imágenes",
"Océanos"};
this.UpdateAuthenticationManager();
}
/// <summary>
///
/// </summary>
/// <param name="vp"></param>
private void UpdateCurrentViewPointAction(Viewpoint vp)
{
this.CurrentViewpoint = vp;
}
/// <summary>
///
/// </summary>
/// <param name="saveMapInfo"></param>
private async void SaveMapAction(SaveMapInfo saveMapInfo)
{
try
{
var currentViewpoint = this.Map.InitialViewpoint;
if (!this.IsMapSaved)
{
await SaveNewMapAsync(currentViewpoint, saveMapInfo.Title, saveMapInfo.Description, saveMapInfo.Tags);
await this.DialogService.DisplayAlertAsync("Mapa Guardado", "Guardado", string.Format("Se guardó {0} en AGOL", saveMapInfo.Title), "OK");
}
else
{
// TODO: update existing portal item
}
}
catch (Exception ex)
{
await this.DialogService.DisplayAlertAsync("No se pudo guardar el mapa", ex.Message, "OK");
}
}
/// <summary>
///
/// </summary>
private void BaseMapsAction()
{
this.IsBasemapListVisible = true;
}
/// <summary>
///
/// </summary>
/// <param name="basemap"></param>
private void ChangeBasemapAction(string basemap)
{
switch (basemap)
{
case "Topográfico":
this.Map.Basemap = Basemap.CreateTopographic();
break;
case "Topográfico Vector":
this.Map.Basemap = Basemap.CreateTopographicVector();
break;
case "Calles":
this.Map.Basemap = Basemap.CreateStreets();
break;
case "Calles Vector":
this.Map.Basemap = Basemap.CreateStreetsVector();
break;
case "Imágenes":
this.Map.Basemap = Basemap.CreateImagery();
break;
case "Océanos":
this.Map.Basemap = Basemap.CreateOceans();
break;
}
this.IsBasemapListVisible = false;
}
private async void ShowSaveMapPageAction()
{
await this.NavigationService.NavigateAsync("SaveMapPage");
var info = new CredentialRequestInfo
{
AuthenticationType = AuthenticationType.Token,
ServiceUri = new Uri(ArcGISOnlineUrl)
};
Credential cred = await AuthenticationManager.Current.GetCredentialAsync(info, false);
AuthenticationManager.Current.AddCredential(cred);
}
public override void OnNavigatedFrom(NavigationParameters parameters)
{
base.OnNavigatedFrom(parameters);
}
/// <summary>
///
/// </summary>
/// <param name="initialViewpoint"></param>
/// <param name="title"></param>
/// <param name="description"></param>
/// <param name="tags"></param>
/// <returns></returns>
public async Task SaveNewMapAsync(Viewpoint initialViewpoint, string title, string description, string[] tags)
{
ArcGISPortal agsOnline = await ArcGISPortal.CreateAsync(new Uri("https://www.arcgis.com/sharing/rest"));
this.Map.InitialViewpoint = initialViewpoint;
await this.Map.SaveAsAsync(agsOnline, null, title, description, tags, null);
}
/// <summary>
///
/// </summary>
/// <param name="info"></param>
/// <returns></returns>
public async Task<Credential> CreateCredentialAsync(CredentialRequestInfo info)
{
Credential credential = null;
try
{
credential = await AuthenticationManager.Current.GenerateCredentialAsync(info.ServiceUri);
}
catch (Exception ex)
{
throw (ex);
}
return credential;
}
/// <summary>
///
/// </summary>
private void UpdateAuthenticationManager()
{
ServerInfo portalServerInfo = new ServerInfo();
portalServerInfo.ServerUri = new Uri(ArcGISOnlineUrl);
portalServerInfo.TokenAuthenticationType = TokenAuthenticationType.OAuthImplicit;
OAuthClientInfo oAuthInfo = new OAuthClientInfo
{
ClientId = AppClientId,
RedirectUri = new Uri(OAuthRedirectUrl)
};
portalServerInfo.OAuthClientInfo = oAuthInfo;
AuthenticationManager thisAuthenticationManager = AuthenticationManager.Current;
thisAuthenticationManager.RegisterServer(portalServerInfo);
thisAuthenticationManager.ChallengeHandler = new ChallengeHandler(CreateCredentialAsync);
}
}
}
Appreciate any help!!
Marcelo.
Solved! Go to Solution.
I find the answer after drink a hot cup of coffe!
The <esriUi:Mapview.Behavior> tag was bad written the right way is like that:
<esriUI:MapView.Behaviors>
</esriUI:MapView.Behaviors>
I find the answer after drink a hot cup of coffe!
The <esriUi:Mapview.Behavior> tag was bad written the right way is like that:
<esriUI:MapView.Behaviors>
</esriUI:MapView.Behaviors>