From e096f97e85be4f5ee7fe88be2b4cfb3b89ec9c06 Mon Sep 17 00:00:00 2001 From: Clemens Date: Fri, 2 Jul 2021 21:18:39 +0200 Subject: [PATCH] Added TileImageLoader.WinUI --- MBTiles/UWP/MBTiles.UWP.csproj | 2 +- MBTiles/WPF/MBTiles.WPF.csproj | 2 +- MapControl/Shared/MapScale.cs | 2 +- MapControl/UWP/Tile.UWP.cs | 10 +-- MapControl/UWP/TileImageLoader.UWP.cs | 27 ------- MapControl/WinUI/MapControl.WinUI.csproj | 4 ++ MapControl/WinUI/TileImageLoader.WinUI.cs | 88 +++++++++++++++++++++++ SQLiteCache/Shared/SQLiteCache.cs | 2 +- SQLiteCache/UWP/SQLiteCache.UWP.cs | 2 +- SQLiteCache/WPF/SQLiteCache.WPF.cs | 2 +- SampleApps/WinUiApp/MainWindow.xaml.cs | 11 +-- 11 files changed, 110 insertions(+), 42 deletions(-) create mode 100644 MapControl/WinUI/TileImageLoader.WinUI.cs diff --git a/MBTiles/UWP/MBTiles.UWP.csproj b/MBTiles/UWP/MBTiles.UWP.csproj index 5efe3731..f937560c 100644 --- a/MBTiles/UWP/MBTiles.UWP.csproj +++ b/MBTiles/UWP/MBTiles.UWP.csproj @@ -57,7 +57,7 @@ 6.2.12 - 1.0.114.2 + 1.0.114.3 diff --git a/MBTiles/WPF/MBTiles.WPF.csproj b/MBTiles/WPF/MBTiles.WPF.csproj index 33b2bf9d..ed4b9afe 100644 --- a/MBTiles/WPF/MBTiles.WPF.csproj +++ b/MBTiles/WPF/MBTiles.WPF.csproj @@ -38,7 +38,7 @@ - + diff --git a/MapControl/Shared/MapScale.cs b/MapControl/Shared/MapScale.cs index 9edb88fe..f4eeaff1 100644 --- a/MapControl/Shared/MapScale.cs +++ b/MapControl/Shared/MapScale.cs @@ -47,7 +47,7 @@ namespace MapControl line.SetBinding(Shape.StrokeProperty, this.GetBinding(nameof(Stroke))); line.SetBinding(Shape.StrokeThicknessProperty, this.GetBinding(nameof(StrokeThickness))); -#if WINDOWS_UWP +#if WINUI || WINDOWS_UWP label.SetBinding(TextBlock.ForegroundProperty, this.GetBinding(nameof(Foreground))); #endif Children.Add(line); diff --git a/MapControl/UWP/Tile.UWP.cs b/MapControl/UWP/Tile.UWP.cs index 39872633..f2984614 100644 --- a/MapControl/UWP/Tile.UWP.cs +++ b/MapControl/UWP/Tile.UWP.cs @@ -3,14 +3,14 @@ // Licensed under the Microsoft Public License (Ms-PL) using System; -#if WINDOWS_UWP -using Windows.UI.Xaml; -using Windows.UI.Xaml.Media; -using Windows.UI.Xaml.Media.Imaging; -#else +#if WINUI using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Media.Imaging; +#else +using Windows.UI.Xaml; +using Windows.UI.Xaml.Media; +using Windows.UI.Xaml.Media.Imaging; #endif namespace MapControl diff --git a/MapControl/UWP/TileImageLoader.UWP.cs b/MapControl/UWP/TileImageLoader.UWP.cs index 548da7cd..116a7c14 100644 --- a/MapControl/UWP/TileImageLoader.UWP.cs +++ b/MapControl/UWP/TileImageLoader.UWP.cs @@ -4,13 +4,8 @@ using System; using System.Threading.Tasks; -#if WINDOWS_UWP using Windows.UI.Core; using Windows.UI.Xaml.Media; -#else -using Microsoft.UI.Dispatching; -using Microsoft.UI.Xaml.Media; -#endif namespace MapControl { @@ -70,7 +65,6 @@ namespace MapControl return SetTileImageAsync(tile, () => tileSource.LoadImageAsync(tile.XIndex, tile.Y, tile.ZoomLevel)); } -#if WINDOWS_UWP public static async Task SetTileImageAsync(Tile tile, Func> loadImageFunc) { var tcs = new TaskCompletionSource(); @@ -90,26 +84,5 @@ namespace MapControl await tcs.Task.ConfigureAwait(false); } -#else - public static Task SetTileImageAsync(Tile tile, Func> loadImageFunc) - { - var tcs = new TaskCompletionSource(); - - tile.Image.DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () => - { - try - { - tile.SetImage(await loadImageFunc()); - tcs.TrySetResult(); - } - catch (Exception ex) - { - tcs.TrySetException(ex); - } - }); - - return tcs.Task; - } -#endif } } diff --git a/MapControl/WinUI/MapControl.WinUI.csproj b/MapControl/WinUI/MapControl.WinUI.csproj index 5b253017..07b36136 100644 --- a/MapControl/WinUI/MapControl.WinUI.csproj +++ b/MapControl/WinUI/MapControl.WinUI.csproj @@ -33,6 +33,10 @@ + + + + diff --git a/MapControl/WinUI/TileImageLoader.WinUI.cs b/MapControl/WinUI/TileImageLoader.WinUI.cs new file mode 100644 index 00000000..7a5d867b --- /dev/null +++ b/MapControl/WinUI/TileImageLoader.WinUI.cs @@ -0,0 +1,88 @@ +// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control +// © 2021 Clemens Fischer +// Licensed under the Microsoft Public License (Ms-PL) + +using System; +using System.IO; +using System.Threading.Tasks; +using Microsoft.UI.Dispatching; +using Microsoft.UI.Xaml.Media; + +namespace MapControl +{ + namespace Caching + { + public interface IImageCache + { + Task> GetAsync(string key); + + Task SetAsync(string key, byte[] buffer, DateTime expiration); + } + } + + public partial class TileImageLoader + { + /// + /// Default folder path where an IImageCache instance may save cached data, i.e. C:\ProgramData\MapControl\TileCache + /// + public static string DefaultCacheFolder + { + get { return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MapControl", "TileCache"); } + } + + /// + /// The IImageCache implementation used to cache tile images. The default is null. + /// + public static Caching.IImageCache Cache { get; set; } + + + private static async Task LoadCachedTileAsync(Tile tile, Uri uri, string cacheKey) + { + var cacheItem = await Cache.GetAsync(cacheKey).ConfigureAwait(false); + var buffer = cacheItem?.Item1; + + if (cacheItem == null || cacheItem.Item2 < DateTime.UtcNow) + { + var response = await ImageLoader.GetHttpResponseAsync(uri).ConfigureAwait(false); + + if (response != null) // download succeeded + { + buffer = response.Buffer; // may be null or empty when no tile available, but still be cached + + await Cache.SetAsync(cacheKey, buffer, GetExpiration(response.MaxAge)).ConfigureAwait(false); + } + } + //else System.Diagnostics.Debug.WriteLine("Cached: " + cacheKey); + + if (buffer != null && buffer.Length > 0) + { + await SetTileImageAsync(tile, () => ImageLoader.LoadImageAsync(buffer)).ConfigureAwait(false); + } + } + + private static Task LoadTileAsync(Tile tile, TileSource tileSource) + { + return SetTileImageAsync(tile, () => tileSource.LoadImageAsync(tile.XIndex, tile.Y, tile.ZoomLevel)); + } + + public static Task SetTileImageAsync(Tile tile, Func> loadImageFunc) + { + var tcs = new TaskCompletionSource(); + + tile.Image.DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, async () => + { + try + { + tile.SetImage(await loadImageFunc()); + tcs.TrySetResult(); + } + catch (Exception ex) + { + tcs.TrySetException(ex); + } + }); + + return tcs.Task; + } + } +} diff --git a/SQLiteCache/Shared/SQLiteCache.cs b/SQLiteCache/Shared/SQLiteCache.cs index 3a5273c9..1fcecfb8 100644 --- a/SQLiteCache/Shared/SQLiteCache.cs +++ b/SQLiteCache/Shared/SQLiteCache.cs @@ -86,7 +86,7 @@ namespace MapControl.Caching return command; } - private SQLiteCommand SetItemCommand(string key, DateTime expiration, byte[] buffer) + private SQLiteCommand SetItemCommand(string key, byte[] buffer, DateTime expiration) { var command = new SQLiteCommand("insert or replace into items (key, expiration, buffer) values (@key, @exp, @buf)", connection); command.Parameters.AddWithValue("@key", key); diff --git a/SQLiteCache/UWP/SQLiteCache.UWP.cs b/SQLiteCache/UWP/SQLiteCache.UWP.cs index bbedd92c..081b897e 100644 --- a/SQLiteCache/UWP/SQLiteCache.UWP.cs +++ b/SQLiteCache/UWP/SQLiteCache.UWP.cs @@ -36,7 +36,7 @@ namespace MapControl.Caching { try { - using (var command = SetItemCommand(key, expiration, buffer)) + using (var command = SetItemCommand(key, buffer, expiration)) { await command.ExecuteNonQueryAsync(); } diff --git a/SQLiteCache/WPF/SQLiteCache.WPF.cs b/SQLiteCache/WPF/SQLiteCache.WPF.cs index bc88fa55..a4da23ad 100644 --- a/SQLiteCache/WPF/SQLiteCache.WPF.cs +++ b/SQLiteCache/WPF/SQLiteCache.WPF.cs @@ -151,7 +151,7 @@ namespace MapControl.Caching try { - using (var command = SetItemCommand(key, cacheItem.Item2, cacheItem.Item1)) + using (var command = SetItemCommand(key, cacheItem.Item1, cacheItem.Item2)) { command.ExecuteNonQuery(); } diff --git a/SampleApps/WinUiApp/MainWindow.xaml.cs b/SampleApps/WinUiApp/MainWindow.xaml.cs index 9dc0f5ae..3e825bc4 100644 --- a/SampleApps/WinUiApp/MainWindow.xaml.cs +++ b/SampleApps/WinUiApp/MainWindow.xaml.cs @@ -19,11 +19,14 @@ namespace WinUiApp { ImageLoader.HttpClient.DefaultRequestHeaders.Add("User-Agent", "XAML Map Control Test Application"); - var appData = Path.Combine( - Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MapControl"); + var bingMapsApiKeyFile = Path.Combine( + Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MapControl", "BingMapsApiKey.txt"); - TileImageLoader.Cache = new ImageFileCache(Path.Combine(appData, "TileCache")); - BingMapsTileLayer.ApiKey = File.ReadAllText(Path.Combine(appData, "BingMapsApiKey.txt"))?.Trim(); + BingMapsTileLayer.ApiKey = File.ReadAllText(bingMapsApiKeyFile)?.Trim(); + + TileImageLoader.Cache = new ImageFileCache(TileImageLoader.DefaultCacheFolder); + //TileImageLoader.Cache = new FileDbCache(TileImageLoader.DefaultCacheFolder); + //TileImageLoader.Cache = new SQLiteCache(TileImageLoader.DefaultCacheFolder); } catch (Exception ex) {