diff --git a/MapControl/Shared/BoundingBox.cs b/MapControl/Shared/BoundingBox.cs
index a7d80897..8b98eaa9 100644
--- a/MapControl/Shared/BoundingBox.cs
+++ b/MapControl/Shared/BoundingBox.cs
@@ -67,7 +67,7 @@ namespace MapControl
if (values.Length != 4)
{
- throw new FormatException("BoundingBox string must be a comma-separated list of four double values.");
+ throw new FormatException("BoundingBox string must be a comma-separated list of four floating point numbers.");
}
return new BoundingBox(
diff --git a/MapControlExtended.sln b/MapControlExtended.sln
index 1c8d5989..d6c33a82 100644
--- a/MapControlExtended.sln
+++ b/MapControlExtended.sln
@@ -64,6 +64,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MBTiles.WinUI", "MBTiles\Wi
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WinUiApp", "SampleApps\WinUiApp\WinUiApp.csproj", "{751EF297-7CF4-4879-BA8F-42661FA68668}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ProjectionDemo", "SampleApps\ProjectionDemo\ProjectionDemo.csproj", "{AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -428,6 +430,22 @@ Global
{751EF297-7CF4-4879-BA8F-42661FA68668}.Release|x86.ActiveCfg = Release|x86
{751EF297-7CF4-4879-BA8F-42661FA68668}.Release|x86.Build.0 = Release|x86
{751EF297-7CF4-4879-BA8F-42661FA68668}.Release|x86.Deploy.0 = Release|x86
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}.Debug|arm64.ActiveCfg = Debug|Any CPU
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}.Debug|arm64.Build.0 = Debug|Any CPU
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}.Debug|x64.Build.0 = Debug|Any CPU
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}.Debug|x86.Build.0 = Debug|Any CPU
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}.Release|arm64.ActiveCfg = Release|Any CPU
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}.Release|arm64.Build.0 = Release|Any CPU
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}.Release|x64.ActiveCfg = Release|Any CPU
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}.Release|x64.Build.0 = Release|Any CPU
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}.Release|x86.ActiveCfg = Release|Any CPU
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -454,6 +472,7 @@ Global
{1F9FBADF-65C0-453D-9B45-7A88044F807F} = {2FDC8B91-FB95-4C57-8183-63587FBFE180}
{817D606F-A22D-485C-89CF-86062C8E97EF} = {CEAD0EA1-A971-4F5F-9EAE-C72F75D1F737}
{751EF297-7CF4-4879-BA8F-42661FA68668} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC}
+ {AC8C7BE0-9E72-434B-8BF3-FAEFAC2E859C} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {458346DD-B23F-4FDC-8F9D-A10F1882A4DB}
diff --git a/SampleApps/ProjectionDemo/MainWindow.xaml.cs b/SampleApps/ProjectionDemo/MainWindow.xaml.cs
index 917c1d5a..3a928aed 100644
--- a/SampleApps/ProjectionDemo/MainWindow.xaml.cs
+++ b/SampleApps/ProjectionDemo/MainWindow.xaml.cs
@@ -6,7 +6,6 @@ using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Net.Http;
-using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
diff --git a/SampleApps/ProjectionDemo/ProjectionDemo.csproj b/SampleApps/ProjectionDemo/ProjectionDemo.csproj
index 2472a479..02bcc573 100644
--- a/SampleApps/ProjectionDemo/ProjectionDemo.csproj
+++ b/SampleApps/ProjectionDemo/ProjectionDemo.csproj
@@ -4,11 +4,11 @@
WinExe
net6.0-windows
true
- 6.1.0
+ 7.0.0
Clemens Fischer
XAML Map Control Map Projection Demo Application
XAML Map Control
- Copyright © 2020 Clemens Fischer
+ Copyright © 2021 Clemens Fischer
diff --git a/SampleApps/Shared/MapLayers.cs b/SampleApps/Shared/MapLayers.cs
deleted file mode 100644
index 2a2ced6e..00000000
--- a/SampleApps/Shared/MapLayers.cs
+++ /dev/null
@@ -1,182 +0,0 @@
-using MapControl;
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-#if WINUI
-using Microsoft.UI;
-using Microsoft.UI.Xaml;
-using Microsoft.UI.Xaml.Media;
-#elif UWP
-using Windows.UI;
-using Windows.UI.Xaml;
-using Windows.UI.Xaml.Media;
-#else
-using System.Windows;
-using System.Windows.Media;
-#endif
-
-namespace SampleApplication
-{
- public class MapLayers : INotifyPropertyChanged
- {
- public event PropertyChangedEventHandler PropertyChanged;
-
- // See https://wiki.openstreetmap.org/wiki/Tile_servers for a list of free OpenStreetMap Tile Servers
-
- private readonly Dictionary mapLayers = new Dictionary
- {
- {
- "OpenStreetMap",
- new MapTileLayer
- {
- TileSource = new TileSource { UriFormat = "https://tile.openstreetmap.org/{z}/{x}/{y}.png" },
- SourceName = "OpenStreetMap",
- Description = "© [OpenStreetMap contributors](http://www.openstreetmap.org/copyright)"
- }
- },
- {
- "OpenStreetMap German",
- new MapTileLayer
- {
- TileSource = new TileSource { UriFormat = "https://{s}.tile.openstreetmap.de/{z}/{x}/{y}.png" },
- SourceName = "OpenStreetMap German",
- Description = "© [OpenStreetMap contributors](http://www.openstreetmap.org/copyright)"
- }
- },
- {
- "OpenStreetMap French",
- new MapTileLayer
- {
- TileSource = new TileSource { UriFormat = "http://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png" },
- SourceName = "OpenStreetMap French",
- Description = "© [OpenStreetMap France](https://www.openstreetmap.fr/mentions-legales/) © [OpenStreetMap contributors](http://www.openstreetmap.org/copyright)"
- }
- },
- {
- "OpenTopoMap",
- new MapTileLayer
- {
- TileSource = new TileSource { UriFormat = "https://tile.opentopomap.org/{z}/{x}/{y}.png" },
- SourceName = "OpenTopoMap",
- Description = "© [OpenTopoMap](https://opentopomap.org/) © [OpenStreetMap contributors](http://www.openstreetmap.org/copyright)",
- MaxZoomLevel = 17
- }
- },
- {
- "Seamarks",
- new MapTileLayer
- {
- TileSource = new TileSource { UriFormat = "http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png" },
- SourceName = "OpenSeaMap",
- MinZoomLevel = 9,
- MaxZoomLevel = 18
- }
- },
- {
- "Bing Maps Road",
- new BingMapsTileLayer
- {
- Mode = BingMapsTileLayer.MapMode.Road,
- SourceName = "Bing Maps Road",
- Description = "© [Microsoft](http://www.bing.com/maps/)"
- }
- },
- {
- "Bing Maps Aerial",
- new BingMapsTileLayer
- {
- Mode = BingMapsTileLayer.MapMode.Aerial,
- SourceName = "Bing Maps Aerial",
- Description = "© [Microsoft](http://www.bing.com/maps/)",
- MapForeground = new SolidColorBrush(Colors.White),
- MapBackground = new SolidColorBrush(Colors.Black)
- }
- },
- {
- "Bing Maps Aerial with Labels",
- new BingMapsTileLayer
- {
- Mode = BingMapsTileLayer.MapMode.AerialWithLabels,
- SourceName = "Bing Maps Hybrid",
- Description = "© [Microsoft](http://www.bing.com/maps/)",
- MapForeground = new SolidColorBrush(Colors.White),
- MapBackground = new SolidColorBrush(Colors.Black)
- }
- },
- {
- "TopPlusOpen WMTS",
- new WmtsTileLayer
- {
- SourceName = "TopPlusOpen",
- Description = "© [BKG](https://gdz.bkg.bund.de/index.php/default/webdienste/topplus-produkte/wmts-topplusopen-wmts-topplus-open.html)",
- CapabilitiesUri = new Uri("https://sgx.geodatenzentrum.de/wmts_topplus_open/1.0.0/WMTSCapabilities.xml")
- }
- },
- {
- "TopPlusOpen WMS",
- new WmsImageLayer
- {
- Description = "© [BKG](https://gdz.bkg.bund.de/index.php/default/webdienste/topplus-produkte/wms-topplusopen-mit-layer-fur-normalausgabe-und-druck-wms-topplus-open.html)",
- ServiceUri = new Uri("https://sgx.geodatenzentrum.de/wms_topplus_open")
- }
- },
- {
- "OpenStreetMap WMS",
- new WmsImageLayer
- {
- Description = "© [terrestris GmbH & Co. KG](http://ows.terrestris.de/) © [OpenStreetMap contributors](http://www.openstreetmap.org/copyright)",
- ServiceUri = new Uri("http://ows.terrestris.de/osm/service")
- }
- },
- };
-
- private string currentMapLayerName = "OpenStreetMap";
-
- public string CurrentMapLayerName
- {
- get { return currentMapLayerName; }
- set
- {
- currentMapLayerName = value;
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentMapLayerName)));
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(CurrentMapLayer)));
- }
- }
-
- public UIElement CurrentMapLayer
- {
- get { return mapLayers[currentMapLayerName]; }
- }
-
- public UIElement SeamarksLayer
- {
- get { return mapLayers["Seamarks"]; }
- }
-
- public List MapLayerNames { get; } = new List
- {
- "OpenStreetMap",
- "OpenStreetMap German",
- "OpenStreetMap French",
- "OpenTopoMap",
- "TopPlusOpen WMTS",
- "TopPlusOpen WMS",
- "OpenStreetMap WMS",
- };
-
- public MapLayers()
- {
- // Add Bing Maps TileLayers with tile URLs retrieved from the Imagery Metadata Service
- // (http://msdn.microsoft.com/en-us/library/ff701716.aspx).
- // A Bing Maps API Key (http://msdn.microsoft.com/en-us/library/ff428642.aspx) is required
- // for using these layers and must be assigned to the static BingMapsTileLayer.ApiKey property.
-
- if (!string.IsNullOrEmpty(BingMapsTileLayer.ApiKey))
- {
- MapLayerNames.Add("Bing Maps Road");
- MapLayerNames.Add("Bing Maps Aerial");
- MapLayerNames.Add("Bing Maps Aerial with Labels");
- }
- }
- }
-}
diff --git a/SampleApps/Shared/MapLayersMenuButton.cs b/SampleApps/Shared/MapLayersMenuButton.cs
new file mode 100644
index 00000000..3716ae92
--- /dev/null
+++ b/SampleApps/Shared/MapLayersMenuButton.cs
@@ -0,0 +1,158 @@
+using MapControl;
+using System.Collections.Generic;
+using System.Linq;
+#if WINUI
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+#elif UWP
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Media;
+#else
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+#endif
+
+namespace SampleApplication
+{
+ public class MapLayersMenuButton : MenuButton
+ {
+ public MapLayersMenuButton()
+ {
+#if WINUI || UWP
+ Content = new FontIcon
+ {
+ FontFamily = new FontFamily("Segoe MDL2 Assets"),
+ Glyph = "\uE81E"
+ };
+#else
+ FontFamily = new FontFamily("Segoe MDL2 Assets");
+ Content = "\uE81E";
+#endif
+ }
+
+ public static readonly DependencyProperty MapProperty = DependencyProperty.Register(
+ nameof(Map), typeof(MapBase), typeof(MapLayersMenuButton),
+ new PropertyMetadata(null, (o, e) => ((MapLayersMenuButton)o).InitializeMenu()));
+
+ public static readonly DependencyProperty MapLayersProperty = DependencyProperty.Register(
+ nameof(MapLayers), typeof(IDictionary), typeof(MapLayersMenuButton),
+ new PropertyMetadata(null, (o, e) => ((MapLayersMenuButton)o).InitializeMenu()));
+
+ public static readonly DependencyProperty MapOverlaysProperty = DependencyProperty.Register(
+ nameof(MapOverlays), typeof(IDictionary), typeof(MapLayersMenuButton),
+ new PropertyMetadata(null, (o, e) => ((MapLayersMenuButton)o).InitializeMenu()));
+
+ public MapBase Map
+ {
+ get { return (MapBase)GetValue(MapProperty); }
+ set { SetValue(MapProperty, value); }
+ }
+
+ public IDictionary MapLayers
+ {
+ get { return (IDictionary)GetValue(MapLayersProperty); }
+ set { SetValue(MapLayersProperty, value); }
+ }
+
+ public IDictionary MapOverlays
+ {
+ get { return (IDictionary)GetValue(MapOverlaysProperty); }
+ set { SetValue(MapOverlaysProperty, value); }
+ }
+
+ private void InitializeMenu()
+ {
+ if (Map != null && MapLayers != null)
+ {
+ var menu = CreateMenu();
+
+ foreach (var layer in MapLayers)
+ {
+ menu.Items.Add(CreateMenuItem(layer.Key, layer.Value, MapLayerClicked));
+ }
+
+ var initialLayer = MapLayers.Values.FirstOrDefault();
+
+ if (MapOverlays != null && MapOverlays.Any())
+ {
+ if (initialLayer != null)
+ {
+ menu.Items.Add(CreateSeparator());
+ }
+
+ foreach (var overlay in MapOverlays)
+ {
+ menu.Items.Add(CreateMenuItem(overlay.Key, overlay.Value, MapOverlayClicked));
+ }
+ }
+
+ if (initialLayer != null)
+ {
+ SetMapLayer(initialLayer);
+ }
+ }
+ }
+
+ private void MapLayerClicked(object sender, RoutedEventArgs e)
+ {
+ var item = (FrameworkElement)sender;
+ var layer = (UIElement)item.Tag;
+
+ SetMapLayer(layer);
+ }
+
+ private void MapOverlayClicked(object sender, RoutedEventArgs e)
+ {
+ var item = (FrameworkElement)sender;
+ var layer = (UIElement)item.Tag;
+
+ ToggleMapOverlay(layer);
+ }
+
+ private void SetMapLayer(UIElement layer)
+ {
+ Map.MapLayer = layer;
+
+ UpdateCheckedStates();
+ }
+
+ private void ToggleMapOverlay(UIElement layer)
+ {
+ if (Map.Children.Contains(layer))
+ {
+ Map.Children.Remove(layer);
+ }
+ else
+ {
+ int index = 1;
+
+ foreach (var overlay in MapOverlays.Values)
+ {
+ if (overlay == layer)
+ {
+ Map.Children.Insert(index, layer);
+ break;
+ }
+
+ if (Map.Children.Contains(overlay))
+ {
+ index++;
+ }
+ }
+ }
+
+ UpdateCheckedStates();
+ }
+
+ private void UpdateCheckedStates()
+ {
+ foreach (var item in GetMenuItems())
+ {
+ item.IsChecked = Map.Children.Contains((UIElement)item.Tag);
+ }
+ }
+ }
+}
diff --git a/SampleApps/Shared/MapProjectionsMenuButton.cs b/SampleApps/Shared/MapProjectionsMenuButton.cs
new file mode 100644
index 00000000..dbd427a5
--- /dev/null
+++ b/SampleApps/Shared/MapProjectionsMenuButton.cs
@@ -0,0 +1,94 @@
+using MapControl;
+using System.Collections.Generic;
+using System.Linq;
+#if WINUI
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+#elif UWP
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Media;
+#else
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+#endif
+
+namespace SampleApplication
+{
+ public class MapProjectionsMenuButton : MenuButton
+ {
+ public MapProjectionsMenuButton()
+ {
+#if WINUI || UWP
+ Content = new FontIcon
+ {
+ FontFamily = new FontFamily("Segoe MDL2 Assets"),
+ Glyph = "\uE809"
+ };
+#else
+ FontFamily = new FontFamily("Segoe MDL2 Assets");
+ Content = "\uE809";
+#endif
+ }
+
+ public static readonly DependencyProperty MapProperty = DependencyProperty.Register(
+ nameof(Map), typeof(MapBase), typeof(MapProjectionsMenuButton),
+ new PropertyMetadata(null, (o, e) => ((MapProjectionsMenuButton)o).InitializeMenu()));
+
+ public static readonly DependencyProperty MapProjectionsProperty = DependencyProperty.Register(
+ nameof(MapProjections), typeof(IDictionary), typeof(MapProjectionsMenuButton),
+ new PropertyMetadata(null, (o, e) => ((MapProjectionsMenuButton)o).InitializeMenu()));
+
+ public MapBase Map
+ {
+ get { return (MapBase)GetValue(MapProperty); }
+ set { SetValue(MapProperty, value); }
+ }
+
+ public IDictionary MapProjections
+ {
+ get { return (IDictionary)GetValue(MapProjectionsProperty); }
+ set { SetValue(MapProjectionsProperty, value); }
+ }
+
+ private void InitializeMenu()
+ {
+ if (Map != null && MapProjections != null)
+ {
+ var menu = CreateMenu();
+
+ foreach (var projection in MapProjections)
+ {
+ menu.Items.Add(CreateMenuItem(projection.Key, projection.Value, MapProjectionClicked));
+ }
+
+ var initialProjection = MapProjections.Values.FirstOrDefault();
+
+ if (initialProjection != null)
+ {
+ SetMapProjection(initialProjection);
+ }
+ }
+ }
+
+ private void MapProjectionClicked(object sender, RoutedEventArgs e)
+ {
+ var item = (FrameworkElement)sender;
+ var projection = (MapProjection)item.Tag;
+
+ SetMapProjection(projection);
+ }
+
+ private void SetMapProjection(MapProjection projection)
+ {
+ Map.MapProjection = projection;
+
+ foreach (var item in GetMenuItems())
+ {
+ item.IsChecked = Map.MapProjection == (MapProjection)item.Tag;
+ }
+ }
+ }
+}
diff --git a/SampleApps/Shared/MapViewModel.cs b/SampleApps/Shared/MapViewModel.cs
index 7b87d53b..27a51042 100644
--- a/SampleApps/Shared/MapViewModel.cs
+++ b/SampleApps/Shared/MapViewModel.cs
@@ -1,95 +1,233 @@
using MapControl;
-using System.Collections.ObjectModel;
-using System.ComponentModel;
+using System;
+using System.Collections.Generic;
+#if WINUI
+using Microsoft.UI;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+using Microsoft.UI.Xaml.Media.Imaging;
+#elif UWP
+using Windows.UI;
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+using Windows.UI.Xaml.Media;
+using Windows.UI.Xaml.Media.Imaging;
+#else
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+#endif
namespace SampleApplication
{
- public class ViewModelBase : INotifyPropertyChanged
+ public class PointItem
{
- public event PropertyChangedEventHandler PropertyChanged;
+ public string Name { get; set; }
- protected void RaisePropertyChanged(string propertyName)
- {
- PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
- }
+ public Location Location { get; set; }
}
- public class PointItem : ViewModelBase
- {
- private string name;
- public string Name
- {
- get { return name; }
- set
- {
- name = value;
- RaisePropertyChanged(nameof(Name));
- }
- }
-
- private Location location;
- public Location Location
- {
- get { return location; }
- set
- {
- location = value;
- RaisePropertyChanged(nameof(Location));
- }
- }
- }
-
- public class Polyline
+ public class PolylineItem
{
public LocationCollection Locations { get; set; }
}
- public class MapViewModel : ViewModelBase
+ public class MapViewModel
{
- private Location mapCenter = new Location(53.5, 8.2);
- public Location MapCenter
+ public List Points { get; } = new List();
+ public List Pushpins { get; } = new List();
+ public List Polylines { get; } = new List();
+
+ public Dictionary MapProjections { get; } = new Dictionary
+ {
+ { "Web Mercator", new WebMercatorProjection() },
+ { "World Mercator", new WorldMercatorProjection() },
+ { "Equirectangular", new EquirectangularProjection() },
+ { "Orthographic", new OrthographicProjection() },
+ { "Gnomonic", new GnomonicProjection() },
+ { "Stereographic", new StereographicProjection() }
+ };
+
+ public Dictionary MapLayers { get; } = new Dictionary
{
- get { return mapCenter; }
- set
{
- mapCenter = value;
- RaisePropertyChanged(nameof(MapCenter));
+ "OpenStreetMap",
+ new MapTileLayer
+ {
+ TileSource = new TileSource { UriFormat = "https://tile.openstreetmap.org/{z}/{x}/{y}.png" },
+ SourceName = "OpenStreetMap",
+ Description = "© [OpenStreetMap contributors](http://www.openstreetmap.org/copyright)"
+ }
+ },
+ {
+ "OpenStreetMap German",
+ new MapTileLayer
+ {
+ TileSource = new TileSource { UriFormat = "https://{s}.tile.openstreetmap.de/{z}/{x}/{y}.png" },
+ SourceName = "OpenStreetMap German",
+ Description = "© [OpenStreetMap contributors](http://www.openstreetmap.org/copyright)"
+ }
+ },
+ {
+ "OpenStreetMap French",
+ new MapTileLayer
+ {
+ TileSource = new TileSource { UriFormat = "http://{s}.tile.openstreetmap.fr/osmfr/{z}/{x}/{y}.png" },
+ SourceName = "OpenStreetMap French",
+ Description = "© [OpenStreetMap France](https://www.openstreetmap.fr/mentions-legales/) © [OpenStreetMap contributors](http://www.openstreetmap.org/copyright)"
+ }
+ },
+ {
+ "OpenTopoMap",
+ new MapTileLayer
+ {
+ TileSource = new TileSource { UriFormat = "https://tile.opentopomap.org/{z}/{x}/{y}.png" },
+ SourceName = "OpenTopoMap",
+ Description = "© [OpenTopoMap](https://opentopomap.org/) © [OpenStreetMap contributors](http://www.openstreetmap.org/copyright)",
+ MaxZoomLevel = 17
+ }
+ },
+ {
+ "TopPlusOpen WMTS",
+ new WmtsTileLayer
+ {
+ SourceName = "TopPlusOpen",
+ Description = "© [BKG](https://gdz.bkg.bund.de/index.php/default/webdienste/topplus-produkte/wmts-topplusopen-wmts-topplus-open.html)",
+ CapabilitiesUri = new Uri("https://sgx.geodatenzentrum.de/wmts_topplus_open/1.0.0/WMTSCapabilities.xml")
+ }
+ },
+ {
+ "TopPlusOpen WMS",
+ new WmsImageLayer
+ {
+ Description = "© [BKG](https://gdz.bkg.bund.de/index.php/default/webdienste/topplus-produkte/wms-topplusopen-mit-layer-fur-normalausgabe-und-druck-wms-topplus-open.html)",
+ ServiceUri = new Uri("https://sgx.geodatenzentrum.de/wms_topplus_open")
+ }
+ },
+ {
+ "OpenStreetMap WMS",
+ new WmsImageLayer
+ {
+ Description = "© [terrestris GmbH & Co. KG](http://ows.terrestris.de/) © [OpenStreetMap contributors](http://www.openstreetmap.org/copyright)",
+ ServiceUri = new Uri("http://ows.terrestris.de/osm/service")
+ }
}
- }
+ };
- public ObservableCollection Points { get; } = new ObservableCollection();
- public ObservableCollection Pushpins { get; } = new ObservableCollection();
- public ObservableCollection Polylines { get; } = new ObservableCollection();
-
- public MapLayers MapLayers { get; } = new MapLayers();
+ public Dictionary MapOverlays { get; } = new Dictionary
+ {
+ {
+ "Sample Image",
+ new Image()
+ },
+ {
+ "Seamarks",
+ new MapTileLayer
+ {
+ TileSource = new TileSource { UriFormat = "http://tiles.openseamap.org/seamark/{z}/{x}/{y}.png" },
+ SourceName = "OpenSeaMap",
+ MinZoomLevel = 9,
+ MaxZoomLevel = 18
+ }
+ },
+ {
+ "Graticule",
+ new MapGraticule
+ {
+ Opacity = 0.75
+ }
+ },
+ {
+ "Scale",
+ new MapScale
+ {
+ HorizontalAlignment = HorizontalAlignment.Center,
+ VerticalAlignment = VerticalAlignment.Bottom
+ }
+ }
+ };
public MapViewModel()
{
+ // Add Bing Maps TileLayers with tile URLs retrieved from the Imagery Metadata Service
+ // (http://msdn.microsoft.com/en-us/library/ff701716.aspx).
+ // A Bing Maps API Key (http://msdn.microsoft.com/en-us/library/ff428642.aspx) is required
+ // for using these layers and must be assigned to the static BingMapsTileLayer.ApiKey property.
+
+ if (!string.IsNullOrEmpty(BingMapsTileLayer.ApiKey))
+ {
+ MapLayers.Add(
+ "Bing Maps Road",
+ new BingMapsTileLayer
+ {
+ Mode = BingMapsTileLayer.MapMode.Road,
+ SourceName = "Bing Maps Road",
+ Description = "© [Microsoft](http://www.bing.com/maps/)"
+ });
+
+ MapLayers.Add(
+ "Bing Maps Aerial",
+ new BingMapsTileLayer
+ {
+ Mode = BingMapsTileLayer.MapMode.Aerial,
+ SourceName = "Bing Maps Aerial",
+ Description = "© [Microsoft](http://www.bing.com/maps/)",
+ MapForeground = new SolidColorBrush(Colors.White),
+ MapBackground = new SolidColorBrush(Colors.Black)
+ });
+
+ MapLayers.Add(
+ "Bing Maps Aerial with Labels",
+ new BingMapsTileLayer
+ {
+ Mode = BingMapsTileLayer.MapMode.AerialWithLabels,
+ SourceName = "Bing Maps Hybrid",
+ Description = "© [Microsoft](http://www.bing.com/maps/)",
+ MapForeground = new SolidColorBrush(Colors.White),
+ MapBackground = new SolidColorBrush(Colors.Black)
+ });
+ }
+
+ var sampleImage = (Image)MapOverlays["Sample Image"];
+#if WINUI || UWP
+ sampleImage.Source = new BitmapImage(new Uri("ms-appx:///10_535_330.jpg"));
+#else
+ sampleImage.Source = new BitmapImage(new Uri("pack://siteoforigin:,,,/10_535_330.jpg"));
+#endif
+ MapPanel.SetBoundingBox(sampleImage, new BoundingBox(53.54031, 8.08594, 53.74871, 8.43750));
+
Points.Add(new PointItem
{
Name = "Steinbake Leitdamm",
Location = new Location(53.51217, 8.16603)
});
+
Points.Add(new PointItem
{
Name = "Buhne 2",
Location = new Location(53.50926, 8.15815)
});
+
Points.Add(new PointItem
{
Name = "Buhne 4",
Location = new Location(53.50468, 8.15343)
});
+
Points.Add(new PointItem
{
Name = "Buhne 6",
Location = new Location(53.50092, 8.15267)
});
+
Points.Add(new PointItem
{
Name = "Buhne 8",
Location = new Location(53.49871, 8.15321)
});
+
Points.Add(new PointItem
{
Name = "Buhne 10",
@@ -101,27 +239,31 @@ namespace SampleApplication
Name = "WHV - Eckwarderhörne",
Location = new Location(53.5495, 8.1877)
});
+
Pushpins.Add(new PointItem
{
Name = "JadeWeserPort",
Location = new Location(53.5914, 8.14)
});
+
Pushpins.Add(new PointItem
{
Name = "Kurhaus Dangast",
Location = new Location(53.447, 8.1114)
});
+
Pushpins.Add(new PointItem
{
Name = "Eckwarderhörne",
Location = new Location(53.5207, 8.2323)
});
- Polylines.Add(new Polyline
+ Polylines.Add(new PolylineItem
{
Locations = LocationCollection.Parse("53.5140,8.1451 53.5123,8.1506 53.5156,8.1623 53.5276,8.1757 53.5491,8.1852 53.5495,8.1877 53.5426,8.1993 53.5184,8.2219 53.5182,8.2386 53.5195,8.2387")
});
- Polylines.Add(new Polyline
+
+ Polylines.Add(new PolylineItem
{
Locations = LocationCollection.Parse("53.5978,8.1212 53.6018,8.1494 53.5859,8.1554 53.5852,8.1531 53.5841,8.1539 53.5802,8.1392 53.5826,8.1309 53.5867,8.1317 53.5978,8.1212")
});
diff --git a/SampleApps/Shared/MenuButton.cs b/SampleApps/Shared/MenuButton.cs
new file mode 100644
index 00000000..02f8d4ee
--- /dev/null
+++ b/SampleApps/Shared/MenuButton.cs
@@ -0,0 +1,73 @@
+using System.Collections.Generic;
+using System.Linq;
+#if WINUI
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+#elif UWP
+using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
+#else
+using System.Windows;
+using System.Windows.Controls;
+#endif
+
+namespace SampleApplication
+{
+ public class MenuButton : Button
+ {
+#if WINUI || UWP
+ protected MenuFlyout CreateMenu()
+ {
+ var menu = new MenuFlyout();
+ Flyout = menu;
+ return menu;
+ }
+
+ protected IEnumerable GetMenuItems()
+ {
+ return ((MenuFlyout)Flyout).Items.OfType();
+ }
+
+ protected static ToggleMenuFlyoutItem CreateMenuItem(string text, object item, RoutedEventHandler click)
+ {
+ var menuItem = new ToggleMenuFlyoutItem { Text = text, Tag = item };
+ menuItem.Click += click;
+ return menuItem;
+ }
+
+ protected static MenuFlyoutSeparator CreateSeparator()
+ {
+ return new MenuFlyoutSeparator();
+ }
+#else
+ protected ContextMenu CreateMenu()
+ {
+ var menu = new ContextMenu();
+ ContextMenu = menu;
+ return menu;
+ }
+
+ protected IEnumerable
+
+
+
+
-
+
+ Always
+
@@ -29,4 +35,9 @@
+
+
+ PreserveNewest
+
+
\ No newline at end of file