2024-07-22 18:06:41 +02:00
|
|
|
|
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
|
2025-01-01 18:57:55 +01:00
|
|
|
|
// Copyright © Clemens Fischer
|
2024-07-22 18:06:41 +02:00
|
|
|
|
// Licensed under the Microsoft Public License (Ms-PL)
|
|
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Collections.Specialized;
|
|
|
|
|
|
using System.Diagnostics;
|
2024-08-30 16:37:40 +02:00
|
|
|
|
using System.IO;
|
2024-07-22 18:06:41 +02:00
|
|
|
|
using System.Linq;
|
2024-09-13 23:47:17 +02:00
|
|
|
|
using System.Threading.Tasks;
|
2024-07-22 18:06:41 +02:00
|
|
|
|
#if WPF
|
|
|
|
|
|
using System.Windows;
|
|
|
|
|
|
#elif UWP
|
|
|
|
|
|
using Windows.UI.Xaml;
|
|
|
|
|
|
#elif WINUI
|
|
|
|
|
|
using Microsoft.UI.Xaml;
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
namespace MapControl
|
|
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// A MapPanel with a collection of GroundOverlay or GeoImage children.
|
|
|
|
|
|
/// </summary>
|
2024-12-31 16:11:37 +01:00
|
|
|
|
public class MapOverlaysPanel : MapPanel
|
2024-07-22 18:06:41 +02:00
|
|
|
|
{
|
|
|
|
|
|
public static readonly DependencyProperty SourcePathsProperty =
|
|
|
|
|
|
DependencyPropertyHelper.Register<MapOverlaysPanel, IEnumerable<string>>(nameof(SourcePaths), null,
|
2025-01-26 21:12:34 +01:00
|
|
|
|
async (control, oldValue, newValue) => await control.SourcePathsPropertyChanged(oldValue, newValue));
|
2024-07-22 18:06:41 +02:00
|
|
|
|
|
|
|
|
|
|
public IEnumerable<string> SourcePaths
|
|
|
|
|
|
{
|
|
|
|
|
|
get => (IEnumerable<string>)GetValue(SourcePathsProperty);
|
|
|
|
|
|
set => SetValue(SourcePathsProperty, value);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-26 21:12:34 +01:00
|
|
|
|
private async Task SourcePathsPropertyChanged(IEnumerable<string> oldSourcePaths, IEnumerable<string> newSourcePaths)
|
2024-07-22 18:06:41 +02:00
|
|
|
|
{
|
|
|
|
|
|
Children.Clear();
|
|
|
|
|
|
|
|
|
|
|
|
if (oldSourcePaths is INotifyCollectionChanged oldCollection)
|
|
|
|
|
|
{
|
|
|
|
|
|
oldCollection.CollectionChanged -= SourcePathsCollectionChanged;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (newSourcePaths != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (newSourcePaths is INotifyCollectionChanged newCollection)
|
|
|
|
|
|
{
|
|
|
|
|
|
newCollection.CollectionChanged += SourcePathsCollectionChanged;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-26 21:12:34 +01:00
|
|
|
|
await AddOverlays(0, newSourcePaths);
|
2024-07-22 18:06:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-02-07 11:12:24 +01:00
|
|
|
|
private async void SourcePathsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
2024-07-22 18:06:41 +02:00
|
|
|
|
{
|
2025-02-07 11:12:24 +01:00
|
|
|
|
switch (e.Action)
|
2024-07-22 18:06:41 +02:00
|
|
|
|
{
|
|
|
|
|
|
case NotifyCollectionChangedAction.Add:
|
2025-02-07 11:12:24 +01:00
|
|
|
|
await AddOverlays(e.NewStartingIndex, e.NewItems.Cast<string>());
|
2024-07-22 18:06:41 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case NotifyCollectionChangedAction.Remove:
|
2025-02-07 11:12:24 +01:00
|
|
|
|
RemoveOverlays(e.OldStartingIndex, e.OldItems.Count);
|
2024-07-22 18:06:41 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case NotifyCollectionChangedAction.Move:
|
2025-02-07 11:12:24 +01:00
|
|
|
|
RemoveOverlays(e.OldStartingIndex, e.OldItems.Count);
|
|
|
|
|
|
await AddOverlays(e.NewStartingIndex, e.NewItems.Cast<string>());
|
2024-07-22 18:06:41 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case NotifyCollectionChangedAction.Replace:
|
2025-02-07 11:12:24 +01:00
|
|
|
|
await ReplaceOverlays(e.NewStartingIndex, e.NewItems.Cast<string>());
|
2024-07-22 18:06:41 +02:00
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case NotifyCollectionChangedAction.Reset:
|
|
|
|
|
|
Children.Clear();
|
2025-01-26 21:12:34 +01:00
|
|
|
|
await AddOverlays(0, SourcePaths);
|
2024-07-22 18:06:41 +02:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-26 21:12:34 +01:00
|
|
|
|
private async Task AddOverlays(int index, IEnumerable<string> sourcePaths)
|
2024-07-22 18:06:41 +02:00
|
|
|
|
{
|
|
|
|
|
|
foreach (var sourcePath in sourcePaths)
|
|
|
|
|
|
{
|
2025-01-26 20:23:42 +01:00
|
|
|
|
Children.Insert(index++, await CreateOverlayAsync(sourcePath));
|
2024-07-22 18:06:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-26 21:12:34 +01:00
|
|
|
|
private async Task ReplaceOverlays(int index, IEnumerable<string> sourcePaths)
|
2024-07-22 18:06:41 +02:00
|
|
|
|
{
|
|
|
|
|
|
foreach (var sourcePath in sourcePaths)
|
|
|
|
|
|
{
|
2025-01-26 20:23:42 +01:00
|
|
|
|
Children[index++] = await CreateOverlayAsync(sourcePath);
|
2024-07-22 18:06:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void RemoveOverlays(int index, int count)
|
|
|
|
|
|
{
|
|
|
|
|
|
while (--count >= 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
Children.RemoveAt(index);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-01-26 20:23:42 +01:00
|
|
|
|
protected virtual async Task<FrameworkElement> CreateOverlayAsync(string sourcePath)
|
2024-07-22 18:06:41 +02:00
|
|
|
|
{
|
|
|
|
|
|
FrameworkElement overlay;
|
2024-08-31 12:47:02 +02:00
|
|
|
|
var ext = Path.GetExtension(sourcePath).ToLower();
|
2024-07-22 18:06:41 +02:00
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ext == ".kmz" || ext == ".kml")
|
|
|
|
|
|
{
|
2024-09-13 23:47:17 +02:00
|
|
|
|
overlay = await GroundOverlay.CreateAsync(sourcePath);
|
2024-07-22 18:06:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2024-09-13 23:47:17 +02:00
|
|
|
|
overlay = await GeoImage.CreateAsync(sourcePath);
|
2024-07-22 18:06:41 +02:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
2024-08-31 16:39:49 +02:00
|
|
|
|
Debug.WriteLine($"{nameof(MapOverlaysPanel)}: {sourcePath}: {ex.Message}");
|
2024-08-31 12:47:02 +02:00
|
|
|
|
|
2024-07-22 18:06:41 +02:00
|
|
|
|
overlay = new MapPanel();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return overlay;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|