I have got a WPF MVVM app where I have a MapView, and the BasemapGallery from the toolkit:
<esri:MapView
x:Name="MainMapView"
Map="{Binding Map}"
/>
<esritoolkit:BasemapGallery
x:Name="BasemapGallery"
GeoModel="{Binding ElementName=MainMapView, Path=Map}"
AvailableBasemaps="{Binding AvailableBasemaps}"/>
The Map property on the VM:
private Map _map;
public Map Map
{
get { return _map; }
set { SetProperty(ref _map, value); }
}
// initialized in VM constructor
Map = new Map
{
InitialViewpoint = new Viewpoint(new MapPoint(X, Y, spatialReference: SpatialReference.Create(3857)), 130617),
Basemap = new Basemap(BasemapStyle.ArcGISTopographic)
};
Changing the mapview's base map from the gallery works fine. The gallery loads base maps from AGOL which is something I would like to override. The app will be on an offline device so I have some map packages locally but I am currently testing with a VectorTileServer base map:
var vectorTiledLayer = new ArcGISVectorTiledLayer(new Uri("https://server/arcgis/rest/services/MyService/VectorTileServer"));
var newBaseMap = new Basemap(vectorTiledLayer)
var item = await BasemapGalleryItem.CreateAsync(newBaseMap);
AvailableBasemaps = new List<BasemapGalleryItem>();
AvailableBasemaps.Add(item);
// where AvailableBasemaps is:
private IList<BasemapGalleryItem> _availableBasemaps;
public IList<BasemapGalleryItem> AvailableBasemaps
{
get { return _availableBasemaps; }
set { SetProperty(ref _availableBasemaps, value); }
}
The gallery is still showing the AGOL base maps, and not at all my custom base map.
What am I doing wrong?
Esri.ArcGISRuntime.WPF v100.15.0
Esri.ArcGISRuntime.Toolkit v100.15.0
Solved! Go to Solution.
If anyone's using Prism, there is a dead simple way to make your own gallery
XAML:
<UserControl x:Class="MapGallery.MapGalleryUC"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<ListView
ItemsSource="{Binding AvailableMaps}"
SelectedValue="{Binding SelectedMap}"
>
<ListView.ItemTemplate>
<DataTemplate>
<WrapPanel>
<Image Source="{Binding Thumbnail}" Height="100" Width="100" />
<Label Content="{Binding Basemap.Name}" VerticalContentAlignment="Center"/>
</WrapPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</UserControl>
VM:
internal class MapGalleryVM : BindableBase
{
private readonly IEventAggregator _eventAggregator;
public MapGalleryVM(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.GetEvent<BasemapsLoadedEvent>().Subscribe(HandleBasemapsLoadedEvent);
}
private void HandleBasemapsLoadedEvent(List<AppBasemap> appMaps)
{
var results = appMaps.Select(x => new MapGalleryModel()
{
Basemap = x.Basemap,
Thumbnail = new BitmapImage(new System.Uri(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, x.MapFileConfig.Thumbnail)))
});
_ = Application.Current.Dispatcher.BeginInvoke(() =>
{
AvailableMaps = new ObservableCollection<MapGalleryModel>(results);
});
}
private ObservableCollection<MapGalleryModel> _availableMaps;
public ObservableCollection<MapGalleryModel> AvailableMaps
{
get { return _availableMaps; }
set { SetProperty(ref _availableMaps, value); }
}
private MapGalleryModel _selectedMap;
public MapGalleryModel SelectedMap
{
get { return _selectedMap; }
set
{
if (value != SelectedMap)
{
SetProperty(ref _selectedMap, value);
_eventAggregator.GetEvent<BasemapChangedEvent>().Publish(value.Basemap);
}
}
}
}
The events
internal class BasemapChangedEvent : PubSubEvent<Basemap>
{
}
internal class BasemapsLoadedEvent: PubSubEvent<List<AppBasemap>>
{
}
public class AppBasemap
{
public Basemap Basemap { get; set; }
public MapFileConfig MapFileConfig { get; set; }
}
where MapFileConfig is just a holder for paths to the maps and thumbnails.
And wherever you handle your Map:
internal class MainMapVM : BindableBase
{
public MainMapVM(IEventAggregator eventAggregator)
{
_eventAggregator.GetEvent<BasemapChangedEvent>().Subscribe(HandleBasemapChangedEvent);
LoadBasemaps().Await();
}
private void HandleBasemapChangedEvent(Basemap obj)
{
Map.Basemap = obj;
}
private async Task LoadBasemaps()
{
var appBasemaps = await _layerProvider.GetAppBasemaps(_isOnline);
Map.Basemap = appBasemaps.First().Basemap;
_eventAggregator.GetEvent<BasemapsLoadedEvent>().Publish(appBasemaps);
}
private Map _map;
public Map Map
{
get { return _map; }
set { SetProperty(ref _map, value); }
}
}