diff --git a/Caches/FileDbCache/FileDbCache.cs b/Caches/FileDbCache/FileDbCache.cs
new file mode 100644
index 00000000..7be602d0
--- /dev/null
+++ b/Caches/FileDbCache/FileDbCache.cs
@@ -0,0 +1,196 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// Copyright © 2024 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+using FileDbNs;
+using Microsoft.Extensions.Caching.Distributed;
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MapControl.Caching
+{
+ ///
+ /// IDistributedCache implementation based on FileDb, a free and simple No-SQL database by EzTools Software.
+ /// See http://www.eztools-software.com/tools/filedb/.
+ ///
+ public class FileDbCache : IDistributedCache, IDisposable
+ {
+ private const string keyField = "Key";
+ private const string valueField = "Value";
+ private const string expiresField = "Expires";
+
+ private readonly FileDb fileDb = new FileDb { AutoFlush = true };
+
+ public FileDbCache(string path)
+ {
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ArgumentException("The path argument must not be null or empty.", nameof(path));
+ }
+
+ if (string.IsNullOrEmpty(Path.GetExtension(path)))
+ {
+ path = Path.Combine(path, "TileCache.fdb");
+ }
+
+ try
+ {
+ fileDb.Open(path);
+ Debug.WriteLine($"FileDbCache: Opened database {path}");
+
+ Clean();
+ }
+ catch
+ {
+ if (File.Exists(path))
+ {
+ File.Delete(path);
+ }
+ else
+ {
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
+ }
+
+ fileDb.Create(path, new Field[]
+ {
+ new Field(keyField, DataTypeEnum.String) { IsPrimaryKey = true },
+ new Field(valueField, DataTypeEnum.Byte) { IsArray = true },
+ new Field(expiresField, DataTypeEnum.DateTime)
+ });
+
+ Debug.WriteLine($"FileDbCache: Created database {path}");
+ }
+ }
+
+ public void Dispose()
+ {
+ fileDb.Dispose();
+ }
+
+ public byte[] Get(string key)
+ {
+ byte[] value = null;
+
+ try
+ {
+ var record = fileDb.GetRecordByKey(key, new string[] { valueField, expiresField }, false);
+
+ if (record != null)
+ {
+ if ((DateTime)record[1] > DateTime.UtcNow)
+ {
+ value = (byte[])record[0];
+ }
+ else
+ {
+ fileDb.DeleteRecordByKey(key);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"FileDbCache.Get({key}): {ex.Message}");
+ }
+
+ return value;
+ }
+
+ public Task GetAsync(string key, CancellationToken token = default)
+ {
+ return Task.FromResult(Get(key));
+ }
+
+ public void Set(string key, byte[] value, DistributedCacheEntryOptions options)
+ {
+ DateTime expiration;
+
+ if (options.AbsoluteExpiration.HasValue)
+ {
+ expiration = options.AbsoluteExpiration.Value.DateTime;
+ }
+ else if (options.AbsoluteExpirationRelativeToNow.HasValue)
+ {
+ expiration = DateTime.UtcNow.Add(options.AbsoluteExpirationRelativeToNow.Value);
+ }
+ else if (options.SlidingExpiration.HasValue)
+ {
+ expiration = DateTime.UtcNow.Add(options.SlidingExpiration.Value);
+ }
+ else
+ {
+ expiration = DateTime.UtcNow.Add(TimeSpan.FromDays(1));
+ }
+
+ var fieldValues = new FieldValues(3)
+ {
+ { valueField, value ?? new byte[0] },
+ { expiresField, expiration }
+ };
+
+ try
+ {
+ if (fileDb.GetRecordByKey(key, new string[0], false) != null)
+ {
+ fileDb.UpdateRecordByKey(key, fieldValues);
+ }
+ else
+ {
+ fieldValues.Add(keyField, key);
+ fileDb.AddRecord(fieldValues);
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"FileDbCache.Set({key}): {ex.Message}");
+ }
+ }
+
+ public Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = default)
+ {
+ Set(key, value, options);
+ return Task.CompletedTask;
+ }
+
+ public void Refresh(string key)
+ {
+ throw new NotSupportedException();
+ }
+
+ public Task RefreshAsync(string key, CancellationToken token = default)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void Remove(string key)
+ {
+ try
+ {
+ fileDb.DeleteRecordByKey(key);
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"FileDbCache.Remove({key}): {ex.Message}");
+ }
+ }
+
+ public Task RemoveAsync(string key, CancellationToken token = default)
+ {
+ Remove(key);
+ return Task.CompletedTask;
+ }
+
+ public void Clean()
+ {
+ var deleted = fileDb.DeleteRecords(new FilterExpression(expiresField, DateTime.UtcNow, ComparisonOperatorEnum.LessThanOrEqual));
+
+ if (deleted > 0)
+ {
+ Debug.WriteLine($"FileDbCache: Deleted {deleted} expired items");
+ fileDb.Clean();
+ }
+ }
+ }
+}
diff --git a/Caches/FileDbCache/FileDbCache.csproj b/Caches/FileDbCache/FileDbCache.csproj
new file mode 100644
index 00000000..56f24ad7
--- /dev/null
+++ b/Caches/FileDbCache/FileDbCache.csproj
@@ -0,0 +1,10 @@
+
+
+ netstandard2.0
+
+
+
+
+
+
+
diff --git a/Caches/SQLiteCache/SQLiteCache.cs b/Caches/SQLiteCache/SQLiteCache.cs
new file mode 100644
index 00000000..6cfdfb82
--- /dev/null
+++ b/Caches/SQLiteCache/SQLiteCache.cs
@@ -0,0 +1,245 @@
+// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
+// Copyright © 2024 Clemens Fischer
+// Licensed under the Microsoft Public License (Ms-PL)
+
+using Microsoft.Extensions.Caching.Distributed;
+using System;
+using System.Data.Common;
+using System.Data.SQLite;
+using System.Diagnostics;
+using System.IO;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MapControl.Caching
+{
+ ///
+ /// IDistributedCache implementation based on SQLite.
+ ///
+ public class SQLiteCache : IDistributedCache, IDisposable
+ {
+ private readonly SQLiteConnection connection;
+
+ public SQLiteCache(string path)
+ {
+ if (string.IsNullOrEmpty(path))
+ {
+ throw new ArgumentException("The path argument must not be null or empty.", nameof(path));
+ }
+
+ if (string.IsNullOrEmpty(Path.GetExtension(path)))
+ {
+ path = Path.Combine(path, "TileCache.sqlite");
+ }
+
+ var connection = new SQLiteConnection("Data Source=" + Path.GetFullPath(path));
+ connection.Open();
+
+ using (var command = new SQLiteCommand("create table if not exists items (key text primary key, expiration integer, buffer blob)", connection))
+ {
+ command.ExecuteNonQuery();
+ }
+
+ Debug.WriteLine($"SQLiteCache: Opened database {path}");
+
+ Clean();
+ }
+
+ public void Dispose()
+ {
+ connection.Dispose();
+ }
+
+ public byte[] Get(string key)
+ {
+ byte[] value = null;
+
+ try
+ {
+ using (var command = GetItemCommand(key))
+ {
+ var reader = command.ExecuteReader();
+
+ if (reader.Read() && !ReadValue(reader, ref value))
+ {
+ Remove(key);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"SQLiteCache.Get({key}): {ex.Message}");
+ }
+
+ return value;
+ }
+
+ public async Task GetAsync(string key, CancellationToken token = default)
+ {
+ byte[] value = null;
+
+ try
+ {
+ using (var command = GetItemCommand(key))
+ {
+ var reader = await command.ExecuteReaderAsync(token);
+
+ if (await reader.ReadAsync() && !ReadValue(reader, ref value))
+ {
+ await RemoveAsync(key);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"SQLiteCache.GetAsync({key}): {ex.Message}");
+ }
+
+ return value;
+ }
+
+ public void Set(string key, byte[] value, DistributedCacheEntryOptions options)
+ {
+ try
+ {
+ using (var command = SetItemCommand(key, value, options))
+ {
+ command.ExecuteNonQuery();
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"SQLiteCache.Set({key}): {ex.Message}");
+ }
+ }
+
+ public async Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = default)
+ {
+ try
+ {
+ using (var command = SetItemCommand(key, value, options))
+ {
+ await command.ExecuteNonQueryAsync(token);
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"SQLiteCache.SetAsync({key}): {ex.Message}");
+ }
+ }
+
+ public void Refresh(string key)
+ {
+ throw new NotSupportedException();
+ }
+
+ public Task RefreshAsync(string key, CancellationToken token = default)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void Remove(string key)
+ {
+ try
+ {
+ using (var command = RemoveItemCommand(key))
+ {
+ command.ExecuteNonQuery();
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"SQLiteCache.Remove({key}): {ex.Message}");
+ }
+ }
+
+ public async Task RemoveAsync(string key, CancellationToken token = default)
+ {
+ try
+ {
+ using (var command = RemoveItemCommand(key))
+ {
+ await command.ExecuteNonQueryAsync();
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"SQLiteCache.RemoveAsync({key}): {ex.Message}");
+ }
+ }
+
+ public void Clean()
+ {
+ using (var command = new SQLiteCommand("delete from items where expiration < @exp", connection))
+ {
+ command.Parameters.AddWithValue("@exp", DateTimeOffset.UtcNow.Ticks);
+ command.ExecuteNonQuery();
+ }
+#if DEBUG
+ using (var command = new SQLiteCommand("select changes()", connection))
+ {
+ var deleted = (long)command.ExecuteScalar();
+ if (deleted > 0)
+ {
+ Debug.WriteLine($"SQLiteCache: Deleted {deleted} expired items");
+ }
+ }
+#endif
+ }
+
+ private SQLiteCommand GetItemCommand(string key)
+ {
+ var command = new SQLiteCommand("select expiration, buffer from items where key = @key", connection);
+ command.Parameters.AddWithValue("@key", key);
+ return command;
+ }
+
+ private SQLiteCommand RemoveItemCommand(string key)
+ {
+ var command = new SQLiteCommand("delete from items where key = @key", connection);
+ command.Parameters.AddWithValue("@key", key);
+ return command;
+ }
+
+ private SQLiteCommand SetItemCommand(string key, byte[] buffer, DistributedCacheEntryOptions options)
+ {
+ DateTimeOffset expiration;
+
+ if (options.AbsoluteExpiration.HasValue)
+ {
+ expiration = options.AbsoluteExpiration.Value;
+ }
+ else if (options.AbsoluteExpirationRelativeToNow.HasValue)
+ {
+ expiration = DateTimeOffset.UtcNow.Add(options.AbsoluteExpirationRelativeToNow.Value);
+ }
+ else if (options.SlidingExpiration.HasValue)
+ {
+ expiration = DateTimeOffset.UtcNow.Add(options.SlidingExpiration.Value);
+ }
+ else
+ {
+ expiration = DateTimeOffset.UtcNow.Add(TimeSpan.FromDays(1));
+ }
+
+ var command = new SQLiteCommand("insert or replace into items (key, expiration, buffer) values (@key, @exp, @buf)", connection);
+ command.Parameters.AddWithValue("@key", key);
+ command.Parameters.AddWithValue("@exp", expiration.Ticks);
+ command.Parameters.AddWithValue("@buf", buffer ?? new byte[0]);
+ return command;
+ }
+
+ private bool ReadValue(DbDataReader reader, ref byte[] value)
+ {
+ var expiration = new DateTimeOffset((long)reader["expiration"], TimeSpan.Zero);
+
+ if (expiration <= DateTimeOffset.UtcNow)
+ {
+ return false;
+ }
+
+ value = (byte[])reader["buffer"];
+ return true;
+ }
+ }
+}
diff --git a/Caches/SQLiteCache/SQLiteCache.csproj b/Caches/SQLiteCache/SQLiteCache.csproj
new file mode 100644
index 00000000..c4c12774
--- /dev/null
+++ b/Caches/SQLiteCache/SQLiteCache.csproj
@@ -0,0 +1,10 @@
+
+
+ netstandard2.0
+
+
+
+
+
+
+
diff --git a/FileDbCache/Shared/FileDbCache.cs b/FileDbCache/Shared/FileDbCache.cs
deleted file mode 100644
index 3f0ab3e0..00000000
--- a/FileDbCache/Shared/FileDbCache.cs
+++ /dev/null
@@ -1,124 +0,0 @@
-// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
-// Copyright © 2023 Clemens Fischer
-// Licensed under the Microsoft Public License (Ms-PL)
-
-using FileDbNs;
-using System;
-using System.Diagnostics;
-using System.IO;
-
-namespace MapControl.Caching
-{
- ///
- /// Image cache implementation based on FileDb, a free and simple No-SQL database by EzTools Software.
- /// See http://www.eztools-software.com/tools/filedb/.
- ///
- public sealed partial class FileDbCache : IDisposable
- {
- private const string keyField = "Key";
- private const string valueField = "Value";
- private const string expiresField = "Expires";
-
- private readonly FileDb fileDb = new FileDb { AutoFlush = true };
-
- public FileDbCache(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentException("The path argument must not be null or empty.", nameof(path));
- }
-
- if (string.IsNullOrEmpty(Path.GetExtension(path)))
- {
- path = Path.Combine(path, "TileCache.fdb");
- }
-
- Open(path);
- }
-
- public void Dispose()
- {
- fileDb.Dispose();
- }
-
- public void Clean()
- {
- var deleted = fileDb.DeleteRecords(new FilterExpression(expiresField, DateTime.UtcNow, ComparisonOperatorEnum.LessThan));
-
- if (deleted > 0)
- {
- Debug.WriteLine($"FileDbCache: Deleted {deleted} expired items");
- fileDb.Clean();
- }
- }
-
- private void Open(string path)
- {
- try
- {
- fileDb.Open(path);
- Debug.WriteLine($"FileDbCache: Opened database {path}");
-
- Clean();
- }
- catch
- {
- if (File.Exists(path))
- {
- File.Delete(path);
- }
- else
- {
- Directory.CreateDirectory(Path.GetDirectoryName(path));
- }
-
- fileDb.Create(path, new Field[]
- {
- new Field(keyField, DataTypeEnum.String) { IsPrimaryKey = true },
- new Field(valueField, DataTypeEnum.Byte) { IsArray = true },
- new Field(expiresField, DataTypeEnum.DateTime)
- });
-
- Debug.WriteLine($"FileDbCache: Created database {path}");
- }
- }
-
- private Record GetRecordByKey(string key)
- {
- try
- {
- return fileDb.GetRecordByKey(key, new string[] { valueField, expiresField }, false);
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"FileDbCache.GetRecordByKey({key}): {ex.Message}");
- }
-
- return null;
- }
-
- private void AddOrUpdateRecord(string key, byte[] buffer, DateTime expiration)
- {
- var fieldValues = new FieldValues(3);
- fieldValues.Add(valueField, buffer ?? new byte[0]);
- fieldValues.Add(expiresField, expiration);
-
- try
- {
- if (fileDb.GetRecordByKey(key, new string[0], false) != null)
- {
- fileDb.UpdateRecordByKey(key, fieldValues);
- }
- else
- {
- fieldValues.Add(keyField, key);
- fileDb.AddRecord(fieldValues);
- }
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"FileDbCache.AddOrUpdateRecord({key}): {ex.Message}");
- }
- }
- }
-}
diff --git a/FileDbCache/UWP/FileDbCache.UWP.csproj b/FileDbCache/UWP/FileDbCache.UWP.csproj
deleted file mode 100644
index dcc0871c..00000000
--- a/FileDbCache/UWP/FileDbCache.UWP.csproj
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
- Debug
- AnyCPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}
- Library
- Properties
- MapControl.Caching
- FileDbCache.UWP
- en-US
- UAP
- 10.0.22000.0
- 10.0.17763.0
- 14
- 512
- {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;UWP
- prompt
- 4
-
-
- AnyCPU
- none
- true
- bin\Release\
- UWP
- prompt
- 4
-
-
- PackageReference
-
-
-
- FileDbCache.cs
-
-
- FileDbCache.WinUI.cs
-
-
-
-
-
-
- 7.4.4
-
-
- 6.2.14
-
-
-
-
- MapControl.snk
-
-
-
-
- {9545f73c-9c35-4cf6-baae-19a0baebd344}
- MapControl.UWP
-
-
-
- 14.0
-
-
- true
-
-
- ..\..\MapControl.snk
-
-
-
\ No newline at end of file
diff --git a/FileDbCache/UWP/Properties/AssemblyInfo.cs b/FileDbCache/UWP/Properties/AssemblyInfo.cs
deleted file mode 100644
index cfb2f4a4..00000000
--- a/FileDbCache/UWP/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System.Reflection;
-using System.Runtime.InteropServices;
-
-[assembly: AssemblyTitle("XAML Map Control FileDbCache Library for UWP")]
-[assembly: AssemblyProduct("XAML Map Control")]
-[assembly: AssemblyCompany("Clemens Fischer")]
-[assembly: AssemblyCopyright("Copyright © 2023 Clemens Fischer")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyVersion("8.3.0")]
-[assembly: AssemblyFileVersion("8.3.0")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCulture("")]
-[assembly: ComVisible(false)]
diff --git a/FileDbCache/UWP/Properties/FileDbCache.UWP.rd.xml b/FileDbCache/UWP/Properties/FileDbCache.UWP.rd.xml
deleted file mode 100644
index 32fbaacb..00000000
--- a/FileDbCache/UWP/Properties/FileDbCache.UWP.rd.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-
diff --git a/FileDbCache/WPF/FileDbCache.WPF.cs b/FileDbCache/WPF/FileDbCache.WPF.cs
deleted file mode 100644
index aff9304a..00000000
--- a/FileDbCache/WPF/FileDbCache.WPF.cs
+++ /dev/null
@@ -1,185 +0,0 @@
-// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
-// Copyright © 2023 Clemens Fischer
-// Licensed under the Microsoft Public License (Ms-PL)
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Runtime.Caching;
-
-namespace MapControl.Caching
-{
- public partial class FileDbCache : ObjectCache
- {
- public override string Name => string.Empty;
-
- public override DefaultCacheCapabilities DefaultCacheCapabilities =>
- DefaultCacheCapabilities.AbsoluteExpirations | DefaultCacheCapabilities.SlidingExpirations;
-
- public override object this[string key]
- {
- get => Get(key);
- set => Set(key, value, null);
- }
-
- protected override IEnumerator> GetEnumerator()
- {
- throw new NotSupportedException("FileDbCache does not support the ability to enumerate items.");
- }
-
- public override CacheEntryChangeMonitor CreateCacheEntryChangeMonitor(IEnumerable keys, string regionName = null)
- {
- throw new NotSupportedException("FileDbCache does not support the ability to create change monitors.");
- }
-
- public override long GetCount(string regionName = null)
- {
- if (regionName != null)
- {
- throw new NotSupportedException("FileDbCache does not support named regions.");
- }
-
- try
- {
- return fileDb.NumRecords;
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"FileDbCache.GetCount(): {ex.Message}");
- }
-
- return 0;
- }
-
- public override bool Contains(string key, string regionName = null)
- {
- if (regionName != null)
- {
- throw new NotSupportedException("FileDbCache does not support named regions.");
- }
-
- if (key == null)
- {
- throw new ArgumentNullException(nameof(key));
- }
-
- try
- {
- return fileDb.GetRecordByKey(key, Array.Empty(), false) != null;
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"FileDbCache.Contains({key}): {ex.Message}");
- }
-
- return false;
- }
-
- public override object Get(string key, string regionName = null)
- {
- if (regionName != null)
- {
- throw new NotSupportedException("FileDbCache does not support named regions.");
- }
-
- if (key == null)
- {
- throw new ArgumentNullException(nameof(key));
- }
-
- var record = GetRecordByKey(key);
-
- if (record == null)
- {
- return null;
- }
-
- return Tuple.Create((byte[])record[0], (DateTime)record[1]);
- }
-
- public override CacheItem GetCacheItem(string key, string regionName = null)
- {
- var value = Get(key, regionName);
-
- return value != null ? new CacheItem(key, value) : null;
- }
-
- public override IDictionary GetValues(IEnumerable keys, string regionName = null)
- {
- return keys.ToDictionary(key => key, key => Get(key, regionName));
- }
-
- public override void Set(string key, object value, CacheItemPolicy policy, string regionName = null)
- {
- if (regionName != null)
- {
- throw new NotSupportedException("FileDbCache does not support named regions.");
- }
-
- if (key == null)
- {
- throw new ArgumentNullException(nameof(key));
- }
-
- if (!(value is Tuple cacheItem))
- {
- throw new ArgumentException("The value argument must be a Tuple.", nameof(value));
- }
-
- AddOrUpdateRecord(key, cacheItem.Item1, cacheItem.Item2);
- }
-
- public override void Set(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
- {
- Set(key, value, new CacheItemPolicy { AbsoluteExpiration = absoluteExpiration }, regionName);
- }
-
- public override void Set(CacheItem item, CacheItemPolicy policy)
- {
- Set(item.Key, item.Value, policy, item.RegionName);
- }
-
- public override object AddOrGetExisting(string key, object value, CacheItemPolicy policy, string regionName = null)
- {
- var oldValue = Get(key, regionName);
-
- Set(key, value, policy);
-
- return oldValue;
- }
-
- public override object AddOrGetExisting(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
- {
- return AddOrGetExisting(key, value, new CacheItemPolicy { AbsoluteExpiration = absoluteExpiration }, regionName);
- }
-
- public override CacheItem AddOrGetExisting(CacheItem item, CacheItemPolicy policy)
- {
- var oldItem = GetCacheItem(item.Key, item.RegionName);
-
- Set(item, policy);
-
- return oldItem;
- }
-
- public override object Remove(string key, string regionName = null)
- {
- var oldValue = Get(key, regionName);
-
- if (oldValue != null)
- {
- try
- {
- fileDb.DeleteRecordByKey(key);
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"FileDbCache.Remove({key}): {ex.Message}");
- }
- }
-
- return oldValue;
- }
- }
-}
diff --git a/FileDbCache/WPF/FileDbCache.WPF.csproj b/FileDbCache/WPF/FileDbCache.WPF.csproj
deleted file mode 100644
index 6b46a7c9..00000000
--- a/FileDbCache/WPF/FileDbCache.WPF.csproj
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
- net8.0-windows;net7.0-windows;net6.0-windows;net48;net462
- true
- MapControl.Caching
- XAML Map Control FileDbCache Library for WPF
- XAML Map Control
- 8.3.0
- Clemens Fischer
- Copyright © 2023 Clemens Fischer
- true
- ..\..\MapControl.snk
- false
- false
- XAML.MapControl.FileDbCache
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/FileDbCache/WinUI/FileDbCache.WinUI.cs b/FileDbCache/WinUI/FileDbCache.WinUI.cs
deleted file mode 100644
index 6cbbc59b..00000000
--- a/FileDbCache/WinUI/FileDbCache.WinUI.cs
+++ /dev/null
@@ -1,32 +0,0 @@
-// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
-// Copyright © 2023 Clemens Fischer
-// Licensed under the Microsoft Public License (Ms-PL)
-
-using System;
-using System.Threading.Tasks;
-
-namespace MapControl.Caching
-{
- public partial class FileDbCache : IImageCache
- {
- public Task> GetAsync(string key)
- {
- return Task.Run(() =>
- {
- var record = GetRecordByKey(key);
-
- if (record == null)
- {
- return null;
- }
-
- return Tuple.Create((byte[])record[0], (DateTime)record[1]);
- });
- }
-
- public Task SetAsync(string key, byte[] buffer, DateTime expiration)
- {
- return Task.Run(() => AddOrUpdateRecord(key, buffer, expiration));
- }
- }
-}
diff --git a/FileDbCache/WinUI/FileDbCache.WinUI.csproj b/FileDbCache/WinUI/FileDbCache.WinUI.csproj
deleted file mode 100644
index 64c29a9d..00000000
--- a/FileDbCache/WinUI/FileDbCache.WinUI.csproj
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
- net8.0-windows10.0.17763.0;net7.0-windows10.0.17763.0;net6.0-windows10.0.17763.0
- win10-x86;win10-x64;win10-arm64
- true
- true
- MapControl.Caching
- XAML Map Control FileDbCache Library for WinUI
- XAML Map Control
- 8.3.0
- Clemens Fischer
- Copyright © 2023 Clemens Fischer
- true
- ..\..\MapControl.snk
- false
- false
- XAML.MapControl.FileDbCache
- WINUI
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/MBTiles/WPF/MBTiles.WPF.csproj b/MBTiles/WPF/MBTiles.WPF.csproj
index 5f82dd8c..846b76c7 100644
--- a/MBTiles/WPF/MBTiles.WPF.csproj
+++ b/MBTiles/WPF/MBTiles.WPF.csproj
@@ -1,6 +1,6 @@
- net7.0-windows;net6.0-windows;net48;net462
+ net6.0-windows;net462
true
MapControl.MBTiles
XAML Map Control MBTiles Library for WPF
diff --git a/MBTiles/WinUI/MBTiles.WinUI.csproj b/MBTiles/WinUI/MBTiles.WinUI.csproj
index 852fa8fa..242dcfc5 100644
--- a/MBTiles/WinUI/MBTiles.WinUI.csproj
+++ b/MBTiles/WinUI/MBTiles.WinUI.csproj
@@ -1,6 +1,6 @@
- net8.0-windows10.0.17763.0;net7.0-windows10.0.17763.0;net6.0-windows10.0.17763.0
+ net6.0-windows10.0.17763.0
win10-x86;win10-x64;win10-arm64
true
true
diff --git a/MapControl/Shared/ImageFileCache.cs b/MapControl/Shared/ImageFileCache.cs
index a3f86afd..270da7c8 100644
--- a/MapControl/Shared/ImageFileCache.cs
+++ b/MapControl/Shared/ImageFileCache.cs
@@ -1,21 +1,22 @@
// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
-// Copyright © 2023 Clemens Fischer
+// Copyright © 2024 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
+using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
+using System.Threading;
using System.Threading.Tasks;
namespace MapControl.Caching
{
///
- /// Image Cache implementation based on local image files.
- /// The only valid data type for cached values is Tuple.
+ /// IDistributedCache implementation based on local image files.
///
- public partial class ImageFileCache
+ public class ImageFileCache : IDistributedCache
{
private const string expiresTag = "EXPIRES:";
@@ -38,6 +39,155 @@ namespace MapControl.Caching
return Task.Factory.StartNew(CleanRootDirectory, TaskCreationOptions.LongRunning);
}
+ public byte[] Get(string key)
+ {
+ byte[] buffer = null;
+ var path = GetPath(key);
+
+ try
+ {
+ if (path != null && File.Exists(path))
+ {
+ buffer = File.ReadAllBytes(path);
+
+ CheckExpiration(path, ref buffer);
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"ImageFileCache: Failed reading {path}: {ex.Message}");
+ }
+
+ return buffer;
+ }
+
+ public async Task GetAsync(string key, CancellationToken token = default)
+ {
+ byte[] buffer = null;
+ var path = GetPath(key);
+
+ try
+ {
+ if (path != null && File.Exists(path))
+ {
+#if NETFRAMEWORK
+ using (var stream = File.OpenRead(path))
+ {
+ buffer = new byte[stream.Length];
+ var offset = 0;
+ while (offset < buffer.Length)
+ {
+ offset += await stream.ReadAsync(buffer, offset, buffer.Length - offset, token).ConfigureAwait(false);
+ }
+ }
+#else
+ buffer = await File.ReadAllBytesAsync(path, token).ConfigureAwait(false);
+#endif
+ CheckExpiration(path, ref buffer);
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"ImageFileCache: Failed reading {path}: {ex.Message}");
+ }
+
+ return buffer;
+ }
+
+ public void Set(string key, byte[] buffer, DistributedCacheEntryOptions options)
+ {
+ var path = GetPath(key);
+
+ if (path != null && buffer != null && buffer.Length > 0)
+ {
+ try
+ {
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
+
+ using (var stream = File.Create(path))
+ {
+ stream.Write(buffer, 0, buffer.Length);
+
+ var expiration = GetExpiration(options);
+
+ if (expiration.HasValue)
+ {
+ stream.Write(Encoding.ASCII.GetBytes(expiresTag), 0, 8);
+ stream.Write(BitConverter.GetBytes(expiration.Value.Ticks), 0, 8);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"ImageFileCache: Failed writing {path}: {ex.Message}");
+ }
+ }
+ }
+
+ public async Task SetAsync(string key, byte[] buffer, DistributedCacheEntryOptions options, CancellationToken token = default)
+ {
+ var path = GetPath(key);
+
+ if (path != null && buffer != null && buffer.Length > 0)
+ {
+ try
+ {
+ Directory.CreateDirectory(Path.GetDirectoryName(path));
+
+ using (var stream = File.Create(path))
+ {
+ await stream.WriteAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
+
+ var expiration = GetExpiration(options);
+
+ if (expiration.HasValue)
+ {
+ await stream.WriteAsync(Encoding.ASCII.GetBytes(expiresTag), 0, 8).ConfigureAwait(false);
+ await stream.WriteAsync(BitConverter.GetBytes(expiration.Value.Ticks), 0, 8).ConfigureAwait(false);
+ }
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"ImageFileCache: Failed writing {path}: {ex.Message}");
+ }
+ }
+ }
+
+ public void Refresh(string key)
+ {
+ throw new NotSupportedException();
+ }
+
+ public Task RefreshAsync(string key, CancellationToken token = default)
+ {
+ throw new NotSupportedException();
+ }
+
+ public void Remove(string key)
+ {
+ var path = GetPath(key);
+
+ try
+ {
+ if (path != null && File.Exists(path))
+ {
+ File.Delete(path);
+ }
+ }
+ catch (Exception ex)
+ {
+ Debug.WriteLine($"ImageFileCache: Failed deleting {path}: {ex.Message}");
+ }
+
+ }
+
+ public Task RemoveAsync(string key, CancellationToken token = default)
+ {
+ Remove(key);
+ return Task.CompletedTask;
+ }
+
private string GetPath(string key)
{
try
@@ -101,7 +251,9 @@ namespace MapControl.Caching
try
{
- if (ReadExpiration(file) < DateTime.UtcNow)
+ var expiration = ReadExpiration(file);
+
+ if (expiration.HasValue && expiration.Value <= DateTimeOffset.UtcNow)
{
file.Delete();
deletedFileCount = 1;
@@ -115,9 +267,40 @@ namespace MapControl.Caching
return deletedFileCount;
}
- private static DateTime ReadExpiration(FileInfo file)
+ private static DateTimeOffset? GetExpiration(DistributedCacheEntryOptions options)
{
- DateTime? expiration = null;
+ DateTimeOffset? expiration = null;
+
+ if (options.AbsoluteExpiration.HasValue)
+ {
+ expiration = options.AbsoluteExpiration.Value;
+ }
+ else if (options.AbsoluteExpirationRelativeToNow.HasValue)
+ {
+ expiration = DateTimeOffset.UtcNow.Add(options.AbsoluteExpirationRelativeToNow.Value);
+ }
+ else if (options.SlidingExpiration.HasValue)
+ {
+ expiration = DateTimeOffset.UtcNow.Add(options.SlidingExpiration.Value);
+ }
+
+ return expiration;
+ }
+
+ private static void CheckExpiration(string path, ref byte[] buffer)
+ {
+ var expiration = ReadExpiration(ref buffer);
+
+ if (expiration.HasValue && expiration.Value <= DateTimeOffset.UtcNow)
+ {
+ File.Delete(path);
+ buffer = null;
+ }
+ }
+
+ private static DateTimeOffset? ReadExpiration(FileInfo file)
+ {
+ DateTimeOffset? expiration = null;
if (file.Length > 16)
{
@@ -134,46 +317,32 @@ namespace MapControl.Caching
}
}
- return expiration ?? DateTime.Today;
+ return expiration;
}
- private static DateTime ReadExpiration(ref byte[] buffer)
+ private static DateTimeOffset? ReadExpiration(ref byte[] buffer)
{
- DateTime? expiration = ReadExpiration(buffer);
+ var expiration = ReadExpiration(buffer);
if (expiration.HasValue)
{
Array.Resize(ref buffer, buffer.Length - 16);
-
- return expiration.Value;
- }
-
- return DateTime.Today;
- }
-
- private static DateTime? ReadExpiration(byte[] buffer)
- {
- DateTime? expiration = null;
-
- if (buffer.Length >= 16 &&
- Encoding.ASCII.GetString(buffer, buffer.Length - 16, 8) == expiresTag)
- {
- expiration = new DateTime(BitConverter.ToInt64(buffer, buffer.Length - 8), DateTimeKind.Utc);
}
return expiration;
}
- private static void WriteExpiration(Stream stream, DateTime expiration)
+ private static DateTimeOffset? ReadExpiration(byte[] buffer)
{
- stream.Write(Encoding.ASCII.GetBytes(expiresTag), 0, 8);
- stream.Write(BitConverter.GetBytes(expiration.Ticks), 0, 8);
- }
+ DateTimeOffset? expiration = null;
- private static async Task WriteExpirationAsync(Stream stream, DateTime expiration)
- {
- await stream.WriteAsync(Encoding.ASCII.GetBytes(expiresTag), 0, 8);
- await stream.WriteAsync(BitConverter.GetBytes(expiration.Ticks), 0, 8);
+ if (buffer.Length >= 16 &&
+ Encoding.ASCII.GetString(buffer, buffer.Length - 16, 8) == expiresTag)
+ {
+ expiration = new DateTimeOffset(BitConverter.ToInt64(buffer, buffer.Length - 8), TimeSpan.Zero);
+ }
+
+ return expiration;
}
}
}
diff --git a/MapControl/Shared/TileImageLoader.cs b/MapControl/Shared/TileImageLoader.cs
index 31bee072..819d0265 100644
--- a/MapControl/Shared/TileImageLoader.cs
+++ b/MapControl/Shared/TileImageLoader.cs
@@ -2,6 +2,7 @@
// Copyright © 2023 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
+using Microsoft.Extensions.Caching.Distributed;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
@@ -39,9 +40,9 @@ namespace MapControl
}
///
- /// Maximum number of parallel tile loading tasks. The default value is 4.
+ /// An IDistributedCache implementation used to cache tile images.
///
- public static int MaxLoadTasks { get; set; } = 4;
+ public static IDistributedCache Cache { get; set; }
///
/// Default expiration time for cached tile images. Used when no expiration time
@@ -55,6 +56,12 @@ namespace MapControl
///
public static TimeSpan MaxCacheExpiration { get; set; } = TimeSpan.FromDays(10);
+ ///
+ /// Maximum number of parallel tile loading tasks. The default value is 4.
+ ///
+ public static int MaxLoadTasks { get; set; } = 4;
+
+
private TileQueue pendingTiles;
///
@@ -125,34 +132,55 @@ namespace MapControl
if (uri != null)
{
- var extension = Path.GetExtension(uri.LocalPath);
-
- if (string.IsNullOrEmpty(extension) || extension == ".jpeg")
- {
- extension = ".jpg";
- }
-
- var cacheKey = string.Format(CultureInfo.InvariantCulture,
- "{0}/{1}/{2}/{3}{4}", cacheName, tile.ZoomLevel, tile.Column, tile.Row, extension);
-
- return LoadCachedTileAsync(tile, uri, cacheKey);
+ return LoadCachedTileAsync(tile, uri, cacheName);
}
return Task.CompletedTask;
}
- private static DateTime GetExpiration(TimeSpan? maxAge)
+ private static async Task LoadCachedTileAsync(Tile tile, Uri uri, string cacheName)
{
- if (!maxAge.HasValue)
+ var extension = Path.GetExtension(uri.LocalPath);
+
+ if (string.IsNullOrEmpty(extension) || extension == ".jpeg")
{
- maxAge = DefaultCacheExpiration;
- }
- else if (maxAge.Value > MaxCacheExpiration)
- {
- maxAge = MaxCacheExpiration;
+ extension = ".jpg";
}
- return DateTime.UtcNow.Add(maxAge.Value);
+ var cacheKey = string.Format(CultureInfo.InvariantCulture,
+ "{0}/{1}/{2}/{3}{4}", cacheName, tile.ZoomLevel, tile.Column, tile.Row, extension);
+
+ var buffer = await Cache.GetAsync(cacheKey).ConfigureAwait(false);
+
+ if (buffer == null)
+ {
+ var response = await ImageLoader.GetHttpResponseAsync(uri).ConfigureAwait(false);
+
+ if (response != null) // download succeeded
+ {
+ buffer = response.Buffer ?? Array.Empty(); // may be empty when no tile available, but still be cached
+
+ var maxAge = response.MaxAge ?? DefaultCacheExpiration;
+
+ if (maxAge > MaxCacheExpiration)
+ {
+ maxAge = MaxCacheExpiration;
+ }
+
+ var cacheOptions = new DistributedCacheEntryOptions
+ {
+ AbsoluteExpiration = DateTimeOffset.UtcNow.Add(maxAge)
+ };
+
+ await Cache.SetAsync(cacheKey, buffer, cacheOptions).ConfigureAwait(false);
+ }
+ }
+ //else System.Diagnostics.Debug.WriteLine($"Cached: {cacheKey}");
+
+ if (buffer != null && buffer.Length > 0)
+ {
+ await LoadTileAsync(tile, () => ImageLoader.LoadImageAsync(buffer)).ConfigureAwait(false);
+ }
}
}
}
diff --git a/MapControl/UWP/MapControl.UWP.csproj b/MapControl/UWP/MapControl.UWP.csproj
index 3dda270e..0a9ce60c 100644
--- a/MapControl/UWP/MapControl.UWP.csproj
+++ b/MapControl/UWP/MapControl.UWP.csproj
@@ -233,9 +233,6 @@
GeoImage.WinUI.cs
-
- ImageFileCache.WinUI.cs
-
ImageLoader.WinUI.cs
@@ -286,6 +283,9 @@
+
+ 8.0.0
+
6.2.14
diff --git a/MapControl/UWP/TileImageLoader.UWP.cs b/MapControl/UWP/TileImageLoader.UWP.cs
index cbff898a..e042464d 100644
--- a/MapControl/UWP/TileImageLoader.UWP.cs
+++ b/MapControl/UWP/TileImageLoader.UWP.cs
@@ -9,16 +9,6 @@ using Windows.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
{
///
@@ -27,35 +17,6 @@ namespace MapControl
///
public static string DefaultCacheFolder => Windows.Storage.ApplicationData.Current.TemporaryFolder.Path;
- ///
- /// An IImageCache implementation used to cache tile images.
- ///
- 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 LoadTileAsync(tile, () => ImageLoader.LoadImageAsync(buffer)).ConfigureAwait(false);
- }
- }
private static async Task LoadTileAsync(Tile tile, Func> loadImageFunc)
{
diff --git a/MapControl/WPF/ImageFileCache.WPF.cs b/MapControl/WPF/ImageFileCache.WPF.cs
deleted file mode 100644
index 9b5ff2fb..00000000
--- a/MapControl/WPF/ImageFileCache.WPF.cs
+++ /dev/null
@@ -1,241 +0,0 @@
-// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
-// Copyright © 2023 Clemens Fischer
-// Licensed under the Microsoft Public License (Ms-PL)
-
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO;
-using System.Linq;
-using System.Runtime.Caching;
-using System.Security.AccessControl;
-using System.Security.Principal;
-
-namespace MapControl.Caching
-{
- public partial class ImageFileCache : ObjectCache
- {
- private static readonly FileSystemAccessRule fullControlRule = new FileSystemAccessRule(
- new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null),
- FileSystemRights.FullControl, AccessControlType.Allow);
-
- private readonly MemoryCache memoryCache = MemoryCache.Default;
-
- public override string Name => string.Empty;
-
- public override DefaultCacheCapabilities DefaultCacheCapabilities => DefaultCacheCapabilities.None;
-
- public override object this[string key]
- {
- get => Get(key);
- set => Set(key, value, null);
- }
-
- protected override IEnumerator> GetEnumerator()
- {
- throw new NotSupportedException("ImageFileCache does not support the ability to enumerate items.");
- }
-
- public override CacheEntryChangeMonitor CreateCacheEntryChangeMonitor(IEnumerable keys, string regionName = null)
- {
- throw new NotSupportedException("ImageFileCache does not support the ability to create change monitors.");
- }
-
- public override long GetCount(string regionName = null)
- {
- throw new NotSupportedException("ImageFileCache does not support the ability to count items.");
- }
-
- public override bool Contains(string key, string regionName = null)
- {
- if (regionName != null)
- {
- throw new NotSupportedException("ImageFileCache does not support named regions.");
- }
-
- if (key == null)
- {
- throw new ArgumentNullException(nameof(key));
- }
-
- if (memoryCache.Contains(key))
- {
- return true;
- }
-
- var path = GetPath(key);
-
- try
- {
- return path != null && File.Exists(path);
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"ImageFileCache: Failed finding {path}: {ex.Message}");
- }
-
- return false;
- }
-
- public override object Get(string key, string regionName = null)
- {
- if (regionName != null)
- {
- throw new NotSupportedException("ImageFileCache does not support named regions.");
- }
-
- if (key == null)
- {
- throw new ArgumentNullException(nameof(key));
- }
-
- var cacheItem = memoryCache.Get(key) as Tuple;
-
- if (cacheItem == null)
- {
- var path = GetPath(key);
-
- try
- {
- if (path != null && File.Exists(path))
- {
- var buffer = File.ReadAllBytes(path);
- var expiration = ReadExpiration(ref buffer);
-
- cacheItem = new Tuple(buffer, expiration);
-
- memoryCache.Set(key, cacheItem, new CacheItemPolicy { AbsoluteExpiration = expiration });
- }
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"ImageFileCache: Failed reading {path}: {ex.Message}");
- }
- }
-
- return cacheItem;
- }
-
- public override CacheItem GetCacheItem(string key, string regionName = null)
- {
- var value = Get(key, regionName);
-
- return value != null ? new CacheItem(key, value) : null;
- }
-
- public override IDictionary GetValues(IEnumerable keys, string regionName = null)
- {
- return keys.ToDictionary(key => key, key => Get(key, regionName));
- }
-
- public override void Set(string key, object value, CacheItemPolicy policy, string regionName = null)
- {
- if (regionName != null)
- {
- throw new NotSupportedException("ImageFileCache does not support named regions.");
- }
-
- if (key == null)
- {
- throw new ArgumentNullException(nameof(key));
- }
-
- if (!(value is Tuple cacheItem))
- {
- throw new ArgumentException("The value argument must be a Tuple.", nameof(value));
- }
-
- memoryCache.Set(key, cacheItem, policy);
-
- var buffer = cacheItem.Item1;
- var path = GetPath(key);
-
- if (buffer != null && buffer.Length > 0 && path != null)
- {
- try
- {
- Directory.CreateDirectory(Path.GetDirectoryName(path));
-
- using (var stream = File.Create(path))
- {
- stream.Write(buffer, 0, buffer.Length);
- WriteExpiration(stream, cacheItem.Item2);
- }
-
- var fileInfo = new FileInfo(path);
- var fileSecurity = fileInfo.GetAccessControl();
- fileSecurity.AddAccessRule(fullControlRule);
- fileInfo.SetAccessControl(fileSecurity);
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"ImageFileCache: Failed writing {path}: {ex.Message}");
- }
- }
- }
-
- public override void Set(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
- {
- Set(key, value, new CacheItemPolicy { AbsoluteExpiration = absoluteExpiration }, regionName);
- }
-
- public override void Set(CacheItem item, CacheItemPolicy policy)
- {
- Set(item.Key, item.Value, policy, item.RegionName);
- }
-
- public override object AddOrGetExisting(string key, object value, CacheItemPolicy policy, string regionName = null)
- {
- var oldValue = Get(key, regionName);
-
- Set(key, value, policy);
-
- return oldValue;
- }
-
- public override object AddOrGetExisting(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
- {
- return AddOrGetExisting(key, value, new CacheItemPolicy { AbsoluteExpiration = absoluteExpiration }, regionName);
- }
-
- public override CacheItem AddOrGetExisting(CacheItem item, CacheItemPolicy policy)
- {
- var oldItem = GetCacheItem(item.Key, item.RegionName);
-
- Set(item, policy);
-
- return oldItem;
- }
-
- public override object Remove(string key, string regionName = null)
- {
- if (regionName != null)
- {
- throw new NotSupportedException("ImageFileCache does not support named regions.");
- }
-
- if (key == null)
- {
- throw new ArgumentNullException(nameof(key));
- }
-
- memoryCache.Remove(key);
-
- var path = GetPath(key);
-
- try
- {
- if (path != null && File.Exists(path))
- {
- File.Delete(path);
- }
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"ImageFileCache: Failed removing {path}: {ex.Message}");
- }
-
- return null;
- }
- }
-}
diff --git a/MapControl/WPF/MapControl.WPF.csproj b/MapControl/WPF/MapControl.WPF.csproj
index 5be9a50f..965fa2e3 100644
--- a/MapControl/WPF/MapControl.WPF.csproj
+++ b/MapControl/WPF/MapControl.WPF.csproj
@@ -1,6 +1,6 @@
- net8.0-windows;net7.0-windows;net6.0-windows;net48;net462
+ net6.0-windows;net462
true
MapControl
XAML Map Control Library for WPF
@@ -24,13 +24,12 @@
-
-
-
-
-
+
-
+
+
+
+
diff --git a/MapControl/WPF/TileImageLoader.WPF.cs b/MapControl/WPF/TileImageLoader.WPF.cs
index 3ac99767..c17b3839 100644
--- a/MapControl/WPF/TileImageLoader.WPF.cs
+++ b/MapControl/WPF/TileImageLoader.WPF.cs
@@ -4,7 +4,6 @@
using System;
using System.IO;
-using System.Runtime.Caching;
using System.Threading.Tasks;
using System.Windows.Media;
@@ -13,42 +12,11 @@ namespace MapControl
public partial class TileImageLoader
{
///
- /// Default folder path where an ObjectCache instance may save cached data, i.e. C:\ProgramData\MapControl\TileCache
+ /// Default folder path where an IImageCache instance may save cached data, i.e. C:\ProgramData\MapControl\TileCache
///
public static string DefaultCacheFolder =>
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MapControl", "TileCache");
- ///
- /// An ObjectCache instance used to cache tile image data. The default value is MemoryCache.Default.
- ///
- public static ObjectCache Cache { get; set; } = MemoryCache.Default;
-
-
- private static async Task LoadCachedTileAsync(Tile tile, Uri uri, string cacheKey)
- {
- var cacheItem = Cache.Get(cacheKey) as Tuple;
- 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
-
- cacheItem = Tuple.Create(buffer, GetExpiration(response.MaxAge));
-
- Cache.Set(cacheKey, cacheItem, new CacheItemPolicy { AbsoluteExpiration = cacheItem.Item2 });
- }
- }
- //else System.Diagnostics.Debug.WriteLine($"Cached: {cacheKey}");
-
- if (buffer != null && buffer.Length > 0)
- {
- await LoadTileAsync(tile, () => ImageLoader.LoadImageAsync(buffer)).ConfigureAwait(false);
- }
- }
private static async Task LoadTileAsync(Tile tile, Func> loadImageFunc)
{
diff --git a/MapControl/WinUI/ImageFileCache.WinUI.cs b/MapControl/WinUI/ImageFileCache.WinUI.cs
deleted file mode 100644
index 57d0283e..00000000
--- a/MapControl/WinUI/ImageFileCache.WinUI.cs
+++ /dev/null
@@ -1,60 +0,0 @@
-// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
-// Copyright © 2023 Clemens Fischer
-// Licensed under the Microsoft Public License (Ms-PL)
-
-using System;
-using System.Diagnostics;
-using System.IO;
-using System.Threading.Tasks;
-
-namespace MapControl.Caching
-{
- public partial class ImageFileCache : IImageCache
- {
- public async Task> GetAsync(string key)
- {
- Tuple cacheItem = null;
- var path = GetPath(key);
-
- try
- {
- if (path != null && File.Exists(path))
- {
- var buffer = await File.ReadAllBytesAsync(path);
- var expiration = ReadExpiration(ref buffer);
-
- cacheItem = Tuple.Create(buffer, expiration);
- }
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"ImageFileCache: Failed reading {path}: {ex.Message}");
- }
-
- return cacheItem;
- }
-
- public async Task SetAsync(string key, byte[] buffer, DateTime expiration)
- {
- var path = GetPath(key);
-
- if (buffer != null && buffer.Length > 0 && path != null)
- {
- try
- {
- Directory.CreateDirectory(Path.GetDirectoryName(path));
-
- using (var stream = File.Create(path))
- {
- await stream.WriteAsync(buffer, 0, buffer.Length);
- await WriteExpirationAsync(stream, expiration);
- }
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"ImageFileCache: Failed writing {path}: {ex.Message}");
- }
- }
- }
- }
-}
diff --git a/MapControl/WinUI/MapControl.WinUI.csproj b/MapControl/WinUI/MapControl.WinUI.csproj
index 935a1b2c..c9becc1e 100644
--- a/MapControl/WinUI/MapControl.WinUI.csproj
+++ b/MapControl/WinUI/MapControl.WinUI.csproj
@@ -1,6 +1,6 @@
- net8.0-windows10.0.17763.0;net7.0-windows10.0.17763.0;net6.0-windows10.0.17763.0
+ net6.0-windows10.0.17763.0
win10-x86;win10-x64;win10-arm64
true
true
@@ -29,5 +29,6 @@
+
diff --git a/MapControl/WinUI/TileImageLoader.WinUI.cs b/MapControl/WinUI/TileImageLoader.WinUI.cs
index 91edf88a..b494c5e6 100644
--- a/MapControl/WinUI/TileImageLoader.WinUI.cs
+++ b/MapControl/WinUI/TileImageLoader.WinUI.cs
@@ -10,16 +10,6 @@ using System.Threading.Tasks;
namespace MapControl
{
- namespace Caching
- {
- public interface IImageCache
- {
- Task> GetAsync(string key);
-
- Task SetAsync(string key, byte[] buffer, DateTime expiration);
- }
- }
-
public partial class TileImageLoader
{
///
@@ -28,35 +18,6 @@ namespace MapControl
public static string DefaultCacheFolder =>
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MapControl", "TileCache");
- ///
- /// An IImageCache implementation used to cache tile images.
- ///
- 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 LoadTileAsync(tile, () => ImageLoader.LoadImageAsync(buffer)).ConfigureAwait(false);
- }
- }
private static Task LoadTileAsync(Tile tile, Func> loadImageFunc)
{
diff --git a/MapControlExtended.sln b/MapControlExtended.sln
index f4663b54..5f48a774 100644
--- a/MapControlExtended.sln
+++ b/MapControlExtended.sln
@@ -15,12 +15,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "MBTiles", "MBTiles", "{CEAD
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MBTiles.WPF", "MBTiles\WPF\MBTiles.WPF.csproj", "{38B18AB6-6E70-4696-8FB4-E8C8E12BF50C}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FileDbCache", "FileDbCache", "{261905DE-9653-4567-B498-1F46BEA2A4F3}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileDbCache.WPF", "FileDbCache\WPF\FileDbCache.WPF.csproj", "{AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileDbCache.UWP", "FileDbCache\UWP\FileDbCache.UWP.csproj", "{BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}"
-EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapControl.UWP", "MapControl\UWP\MapControl.UWP.csproj", "{9545F73C-9C35-4CF6-BAAE-19A0BAEBD344}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBTiles.UWP", "MBTiles\UWP\MBTiles.UWP.csproj", "{DCC111E9-EC8B-492A-A09D-DF390D83AE8D}"
@@ -33,18 +27,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfApplication", "SampleApp
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MapProjections.UWP", "MapProjections\UWP\MapProjections.UWP.csproj", "{9EE69591-5EDC-45E3-893E-2F9A4B82D538}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SQLiteCache", "SQLiteCache", "{96FD1258-1597-48A2-8D64-1ADAE13E886A}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLiteCache.UWP", "SQLiteCache\UWP\SQLiteCache.UWP.csproj", "{56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SQLiteCache.WPF", "SQLiteCache\WPF\SQLiteCache.WPF.csproj", "{0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapControl.WinUI", "MapControl\WinUI\MapControl.WinUI.csproj", "{ACA8E56C-0F82-4010-A83E-2DBFF5D16919}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FileDbCache.WinUI", "FileDbCache\WinUI\FileDbCache.WinUI.csproj", "{DFE09FD5-530D-48AB-8A46-4611F21BBBC3}"
-EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SQLiteCache.WinUI", "SQLiteCache\WinUI\SQLiteCache.WinUI.csproj", "{E33FC359-F713-462C-8A8E-7EEA15E36BE1}"
-EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapProjections.WinUI", "MapProjections\WinUI\MapProjections.WinUI.csproj", "{3572F71A-83FE-459D-8370-002CA28827FE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MBTiles.WinUI", "MBTiles\WinUI\MBTiles.WinUI.csproj", "{817D606F-A22D-485C-89CF-86062C8E97EF}"
@@ -61,6 +45,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapUiTools.WinUI", "MapUiTo
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MapUiTools.WPF", "MapUiTools\WPF\MapUiTools.WPF.csproj", "{12430DAE-DC53-4C37-95D5-B8923B5FD3D7}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Caches", "Caches", "{69E6CD1A-5619-4549-95FF-2FD126F1A5D2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileDbCache", "Caches\FileDbCache\FileDbCache.csproj", "{E5A7A66A-36EC-4775-850A-A64253DF0383}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SQLiteCache", "Caches\SQLiteCache\SQLiteCache.csproj", "{FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -129,38 +119,6 @@ Global
{38B18AB6-6E70-4696-8FB4-E8C8E12BF50C}.Release|x64.Build.0 = Release|Any CPU
{38B18AB6-6E70-4696-8FB4-E8C8E12BF50C}.Release|x86.ActiveCfg = Release|Any CPU
{38B18AB6-6E70-4696-8FB4-E8C8E12BF50C}.Release|x86.Build.0 = Release|Any CPU
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Debug|arm64.ActiveCfg = Debug|Any CPU
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Debug|arm64.Build.0 = Debug|Any CPU
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Debug|x64.ActiveCfg = Debug|Any CPU
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Debug|x64.Build.0 = Debug|Any CPU
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Debug|x86.ActiveCfg = Debug|Any CPU
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Debug|x86.Build.0 = Debug|Any CPU
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Release|Any CPU.Build.0 = Release|Any CPU
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Release|arm64.ActiveCfg = Release|Any CPU
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Release|arm64.Build.0 = Release|Any CPU
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Release|x64.ActiveCfg = Release|Any CPU
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Release|x64.Build.0 = Release|Any CPU
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Release|x86.ActiveCfg = Release|Any CPU
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133}.Release|x86.Build.0 = Release|Any CPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}.Debug|arm64.ActiveCfg = Debug|Any CPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}.Debug|arm64.Build.0 = Debug|Any CPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}.Debug|x64.ActiveCfg = Debug|Any CPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}.Debug|x64.Build.0 = Debug|Any CPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}.Debug|x86.ActiveCfg = Debug|Any CPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}.Debug|x86.Build.0 = Debug|Any CPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}.Release|Any CPU.Build.0 = Release|Any CPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}.Release|arm64.ActiveCfg = Release|Any CPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}.Release|arm64.Build.0 = Release|Any CPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}.Release|x64.ActiveCfg = Release|Any CPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}.Release|x64.Build.0 = Release|Any CPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}.Release|x86.ActiveCfg = Release|Any CPU
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D}.Release|x86.Build.0 = Release|Any CPU
{9545F73C-9C35-4CF6-BAAE-19A0BAEBD344}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9545F73C-9C35-4CF6-BAAE-19A0BAEBD344}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9545F73C-9C35-4CF6-BAAE-19A0BAEBD344}.Debug|arm64.ActiveCfg = Debug|Any CPU
@@ -241,38 +199,6 @@ Global
{9EE69591-5EDC-45E3-893E-2F9A4B82D538}.Release|x64.Build.0 = Release|Any CPU
{9EE69591-5EDC-45E3-893E-2F9A4B82D538}.Release|x86.ActiveCfg = Release|Any CPU
{9EE69591-5EDC-45E3-893E-2F9A4B82D538}.Release|x86.Build.0 = Release|Any CPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Debug|arm64.ActiveCfg = Debug|Any CPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Debug|arm64.Build.0 = Debug|Any CPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Debug|x64.ActiveCfg = Debug|Any CPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Debug|x64.Build.0 = Debug|Any CPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Debug|x86.ActiveCfg = Debug|Any CPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Debug|x86.Build.0 = Debug|Any CPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Release|Any CPU.Build.0 = Release|Any CPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Release|arm64.ActiveCfg = Release|Any CPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Release|arm64.Build.0 = Release|Any CPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Release|x64.ActiveCfg = Release|Any CPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Release|x64.Build.0 = Release|Any CPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Release|x86.ActiveCfg = Release|Any CPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}.Release|x86.Build.0 = Release|Any CPU
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Debug|arm64.ActiveCfg = Debug|Any CPU
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Debug|arm64.Build.0 = Debug|Any CPU
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Debug|x64.ActiveCfg = Debug|Any CPU
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Debug|x64.Build.0 = Debug|Any CPU
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Debug|x86.ActiveCfg = Debug|Any CPU
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Debug|x86.Build.0 = Debug|Any CPU
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|Any CPU.Build.0 = Release|Any CPU
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|arm64.ActiveCfg = Release|Any CPU
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|arm64.Build.0 = Release|Any CPU
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|x64.ActiveCfg = Release|Any CPU
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|x64.Build.0 = Release|Any CPU
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|x86.ActiveCfg = Release|Any CPU
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349}.Release|x86.Build.0 = Release|Any CPU
{ACA8E56C-0F82-4010-A83E-2DBFF5D16919}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ACA8E56C-0F82-4010-A83E-2DBFF5D16919}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ACA8E56C-0F82-4010-A83E-2DBFF5D16919}.Debug|arm64.ActiveCfg = Debug|Any CPU
@@ -289,38 +215,6 @@ Global
{ACA8E56C-0F82-4010-A83E-2DBFF5D16919}.Release|x64.Build.0 = Release|Any CPU
{ACA8E56C-0F82-4010-A83E-2DBFF5D16919}.Release|x86.ActiveCfg = Release|Any CPU
{ACA8E56C-0F82-4010-A83E-2DBFF5D16919}.Release|x86.Build.0 = Release|Any CPU
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3}.Debug|arm64.ActiveCfg = Debug|Any CPU
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3}.Debug|arm64.Build.0 = Debug|Any CPU
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3}.Debug|x64.ActiveCfg = Debug|Any CPU
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3}.Debug|x64.Build.0 = Debug|Any CPU
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3}.Debug|x86.ActiveCfg = Debug|Any CPU
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3}.Debug|x86.Build.0 = Debug|Any CPU
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3}.Release|Any CPU.Build.0 = Release|Any CPU
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3}.Release|arm64.ActiveCfg = Release|Any CPU
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3}.Release|arm64.Build.0 = Release|Any CPU
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3}.Release|x64.ActiveCfg = Release|Any CPU
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3}.Release|x64.Build.0 = Release|Any CPU
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3}.Release|x86.ActiveCfg = Release|Any CPU
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3}.Release|x86.Build.0 = Release|Any CPU
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1}.Debug|arm64.ActiveCfg = Debug|Any CPU
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1}.Debug|arm64.Build.0 = Debug|Any CPU
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1}.Debug|x64.ActiveCfg = Debug|Any CPU
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1}.Debug|x64.Build.0 = Debug|Any CPU
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1}.Debug|x86.ActiveCfg = Debug|Any CPU
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1}.Debug|x86.Build.0 = Debug|Any CPU
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1}.Release|Any CPU.Build.0 = Release|Any CPU
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1}.Release|arm64.ActiveCfg = Release|Any CPU
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1}.Release|arm64.Build.0 = Release|Any CPU
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1}.Release|x64.ActiveCfg = Release|Any CPU
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1}.Release|x64.Build.0 = Release|Any CPU
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1}.Release|x86.ActiveCfg = Release|Any CPU
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1}.Release|x86.Build.0 = Release|Any CPU
{3572F71A-83FE-459D-8370-002CA28827FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3572F71A-83FE-459D-8370-002CA28827FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3572F71A-83FE-459D-8370-002CA28827FE}.Debug|arm64.ActiveCfg = Debug|Any CPU
@@ -441,6 +335,38 @@ Global
{12430DAE-DC53-4C37-95D5-B8923B5FD3D7}.Release|x64.Build.0 = Release|Any CPU
{12430DAE-DC53-4C37-95D5-B8923B5FD3D7}.Release|x86.ActiveCfg = Release|Any CPU
{12430DAE-DC53-4C37-95D5-B8923B5FD3D7}.Release|x86.Build.0 = Release|Any CPU
+ {E5A7A66A-36EC-4775-850A-A64253DF0383}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E5A7A66A-36EC-4775-850A-A64253DF0383}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E5A7A66A-36EC-4775-850A-A64253DF0383}.Debug|arm64.ActiveCfg = Debug|Any CPU
+ {E5A7A66A-36EC-4775-850A-A64253DF0383}.Debug|arm64.Build.0 = Debug|Any CPU
+ {E5A7A66A-36EC-4775-850A-A64253DF0383}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E5A7A66A-36EC-4775-850A-A64253DF0383}.Debug|x64.Build.0 = Debug|Any CPU
+ {E5A7A66A-36EC-4775-850A-A64253DF0383}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E5A7A66A-36EC-4775-850A-A64253DF0383}.Debug|x86.Build.0 = Debug|Any CPU
+ {E5A7A66A-36EC-4775-850A-A64253DF0383}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E5A7A66A-36EC-4775-850A-A64253DF0383}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E5A7A66A-36EC-4775-850A-A64253DF0383}.Release|arm64.ActiveCfg = Release|Any CPU
+ {E5A7A66A-36EC-4775-850A-A64253DF0383}.Release|arm64.Build.0 = Release|Any CPU
+ {E5A7A66A-36EC-4775-850A-A64253DF0383}.Release|x64.ActiveCfg = Release|Any CPU
+ {E5A7A66A-36EC-4775-850A-A64253DF0383}.Release|x64.Build.0 = Release|Any CPU
+ {E5A7A66A-36EC-4775-850A-A64253DF0383}.Release|x86.ActiveCfg = Release|Any CPU
+ {E5A7A66A-36EC-4775-850A-A64253DF0383}.Release|x86.Build.0 = Release|Any CPU
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}.Debug|arm64.ActiveCfg = Debug|Any CPU
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}.Debug|arm64.Build.0 = Debug|Any CPU
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}.Debug|x64.Build.0 = Debug|Any CPU
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}.Debug|x86.Build.0 = Debug|Any CPU
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}.Release|arm64.ActiveCfg = Release|Any CPU
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}.Release|arm64.Build.0 = Release|Any CPU
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}.Release|x64.ActiveCfg = Release|Any CPU
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}.Release|x64.Build.0 = Release|Any CPU
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}.Release|x86.ActiveCfg = Release|Any CPU
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -449,18 +375,12 @@ Global
{A204A102-C745-4D65-AEC8-7B96FAEDEF2D} = {52AECE49-F314-4F76-98F2-FA800F07824B}
{AA62B4AA-1CA3-4C20-BEB7-B824D0FC4BD1} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC}
{38B18AB6-6E70-4696-8FB4-E8C8E12BF50C} = {CEAD0EA1-A971-4F5F-9EAE-C72F75D1F737}
- {AD1CB53E-7AA4-4EC0-B901-B4E0E2665133} = {261905DE-9653-4567-B498-1F46BEA2A4F3}
- {BEEB142A-5FA3-468D-810A-32A4A5BD6D5D} = {261905DE-9653-4567-B498-1F46BEA2A4F3}
{9545F73C-9C35-4CF6-BAAE-19A0BAEBD344} = {52AECE49-F314-4F76-98F2-FA800F07824B}
{DCC111E9-EC8B-492A-A09D-DF390D83AE8D} = {CEAD0EA1-A971-4F5F-9EAE-C72F75D1F737}
{426C21C0-5F14-491F-BCD1-6D2993510420} = {7BC11E28-8D3B-4C5B-AC08-AB249CC95F6D}
{F92DA93D-75DB-4308-A5F9-6B4C3908A675} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC}
{9EE69591-5EDC-45E3-893E-2F9A4B82D538} = {7BC11E28-8D3B-4C5B-AC08-AB249CC95F6D}
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1} = {96FD1258-1597-48A2-8D64-1ADAE13E886A}
- {0109C2F0-BA2C-420F-B2CA-DB5B29B1A349} = {96FD1258-1597-48A2-8D64-1ADAE13E886A}
{ACA8E56C-0F82-4010-A83E-2DBFF5D16919} = {52AECE49-F314-4F76-98F2-FA800F07824B}
- {DFE09FD5-530D-48AB-8A46-4611F21BBBC3} = {261905DE-9653-4567-B498-1F46BEA2A4F3}
- {E33FC359-F713-462C-8A8E-7EEA15E36BE1} = {96FD1258-1597-48A2-8D64-1ADAE13E886A}
{3572F71A-83FE-459D-8370-002CA28827FE} = {7BC11E28-8D3B-4C5B-AC08-AB249CC95F6D}
{817D606F-A22D-485C-89CF-86062C8E97EF} = {CEAD0EA1-A971-4F5F-9EAE-C72F75D1F737}
{751EF297-7CF4-4879-BA8F-42661FA68668} = {8F2103C2-78AF-4810-8FB9-67572F50C8FC}
@@ -468,6 +388,8 @@ Global
{DFFE8E49-AA07-457E-A459-99326B44F828} = {90C681E9-12AE-4B5F-932D-7EF5D35D8436}
{C412209E-D81D-4ACB-BECD-FEEF52B93468} = {90C681E9-12AE-4B5F-932D-7EF5D35D8436}
{12430DAE-DC53-4C37-95D5-B8923B5FD3D7} = {90C681E9-12AE-4B5F-932D-7EF5D35D8436}
+ {E5A7A66A-36EC-4775-850A-A64253DF0383} = {69E6CD1A-5619-4549-95FF-2FD126F1A5D2}
+ {FDD70FB5-3B6D-43DF-8C2E-04100315C8BC} = {69E6CD1A-5619-4549-95FF-2FD126F1A5D2}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {458346DD-B23F-4FDC-8F9D-A10F1882A4DB}
diff --git a/MapProjections/WPF/MapProjections.WPF.csproj b/MapProjections/WPF/MapProjections.WPF.csproj
index acee5d35..d88efb94 100644
--- a/MapProjections/WPF/MapProjections.WPF.csproj
+++ b/MapProjections/WPF/MapProjections.WPF.csproj
@@ -1,6 +1,6 @@
- net8.0-windows;net7.0-windows;net6.0-windows;net48;net462
+ net6.0-windows;net462
true
MapControl.Projections
XAML Map Control Projections Library for WPF
@@ -24,7 +24,7 @@
-
+
diff --git a/MapProjections/WinUI/MapProjections.WinUI.csproj b/MapProjections/WinUI/MapProjections.WinUI.csproj
index 19923426..8785c637 100644
--- a/MapProjections/WinUI/MapProjections.WinUI.csproj
+++ b/MapProjections/WinUI/MapProjections.WinUI.csproj
@@ -1,6 +1,6 @@
- net8.0-windows10.0.17763.0;net7.0-windows10.0.17763.0;net6.0-windows10.0.17763.0
+ net6.0-windows10.0.17763.0
win10-x86;win10-x64;win10-arm64
true
true
diff --git a/MapUiTools/WPF/MapUiTools.WPF.csproj b/MapUiTools/WPF/MapUiTools.WPF.csproj
index 59fed734..f8abc6a3 100644
--- a/MapUiTools/WPF/MapUiTools.WPF.csproj
+++ b/MapUiTools/WPF/MapUiTools.WPF.csproj
@@ -1,6 +1,6 @@
- net8.0-windows;net7.0-windows;net6.0-windows;net48;net462
+ net6.0-windows;net462
true
MapControl.UiTools
XAML Map Control UI Tools Library for WPF
diff --git a/MapUiTools/WinUI/MapUiTools.WinUI.csproj b/MapUiTools/WinUI/MapUiTools.WinUI.csproj
index d8dc9d54..2200deec 100644
--- a/MapUiTools/WinUI/MapUiTools.WinUI.csproj
+++ b/MapUiTools/WinUI/MapUiTools.WinUI.csproj
@@ -1,6 +1,6 @@
- net8.0-windows10.0.17763.0;net7.0-windows10.0.17763.0;net6.0-windows10.0.17763.0
+ net6.0-windows10.0.17763.0
win10-x86;win10-x64;win10-arm64
true
true
diff --git a/SQLiteCache/Shared/SQLiteCache.cs b/SQLiteCache/Shared/SQLiteCache.cs
deleted file mode 100644
index e7371819..00000000
--- a/SQLiteCache/Shared/SQLiteCache.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
-// Copyright © 2023 Clemens Fischer
-// Licensed under the Microsoft Public License (Ms-PL)
-
-using System;
-using System.Data.SQLite;
-using System.Diagnostics;
-using System.IO;
-
-namespace MapControl.Caching
-{
- ///
- /// Image cache implementation based on SqLite.
- ///
- public sealed partial class SQLiteCache : IDisposable
- {
- private readonly SQLiteConnection connection;
-
- public SQLiteCache(string path)
- {
- if (string.IsNullOrEmpty(path))
- {
- throw new ArgumentException("The path argument must not be null or empty.", nameof(path));
- }
-
- if (string.IsNullOrEmpty(Path.GetExtension(path)))
- {
- path = Path.Combine(path, "TileCache.sqlite");
- }
-
- connection = Open(Path.GetFullPath(path));
-
- Clean();
- }
-
- private static SQLiteConnection Open(string path)
- {
- var connection = new SQLiteConnection("Data Source=" + path);
- connection.Open();
-
- using (var command = new SQLiteCommand("create table if not exists items (key text primary key, expiration integer, buffer blob)", connection))
- {
- command.ExecuteNonQuery();
- }
-
- Debug.WriteLine($"SQLiteCache: Opened database {path}");
-
- return connection;
- }
-
- public void Dispose()
- {
- connection.Dispose();
- }
-
- public void Clean()
- {
- using (var command = new SQLiteCommand("delete from items where expiration < @exp", connection))
- {
- command.Parameters.AddWithValue("@exp", DateTime.UtcNow.Ticks);
- command.ExecuteNonQuery();
- }
-#if DEBUG
- using (var command = new SQLiteCommand("select changes()", connection))
- {
- var deleted = (long)command.ExecuteScalar();
- if (deleted > 0)
- {
- Debug.WriteLine($"SQLiteCache: Deleted {deleted} expired items");
- }
- }
-#endif
- }
-
- private SQLiteCommand RemoveItemCommand(string key)
- {
- var command = new SQLiteCommand("delete from items where key = @key", connection);
- command.Parameters.AddWithValue("@key", key);
- return command;
- }
-
- private SQLiteCommand GetItemCommand(string key)
- {
- var command = new SQLiteCommand("select expiration, buffer from items where key = @key", connection);
- command.Parameters.AddWithValue("@key", key);
- return command;
- }
-
- 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);
- command.Parameters.AddWithValue("@exp", expiration.Ticks);
- command.Parameters.AddWithValue("@buf", buffer ?? new byte[0]);
- return command;
- }
- }
-}
diff --git a/SQLiteCache/UWP/Properties/AssemblyInfo.cs b/SQLiteCache/UWP/Properties/AssemblyInfo.cs
deleted file mode 100644
index f44b7f5c..00000000
--- a/SQLiteCache/UWP/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using System.Reflection;
-using System.Runtime.InteropServices;
-
-[assembly: AssemblyTitle("XAML Map Control SQLiteCache Library for UWP")]
-[assembly: AssemblyProduct("XAML Map Control")]
-[assembly: AssemblyCompany("Clemens Fischer")]
-[assembly: AssemblyCopyright("Copyright © 2023 Clemens Fischer")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyVersion("8.3.0")]
-[assembly: AssemblyFileVersion("8.3.0")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCulture("")]
-[assembly: ComVisible(false)]
diff --git a/SQLiteCache/UWP/Properties/SQLiteCache.UWP.rd.xml b/SQLiteCache/UWP/Properties/SQLiteCache.UWP.rd.xml
deleted file mode 100644
index efe89ca3..00000000
--- a/SQLiteCache/UWP/Properties/SQLiteCache.UWP.rd.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/SQLiteCache/UWP/SQLiteCache.UWP.csproj b/SQLiteCache/UWP/SQLiteCache.UWP.csproj
deleted file mode 100644
index f8834207..00000000
--- a/SQLiteCache/UWP/SQLiteCache.UWP.csproj
+++ /dev/null
@@ -1,81 +0,0 @@
-
-
-
-
- Debug
- AnyCPU
- {56DFA7CF-F31D-45CE-9C36-DA8DBB8413B1}
- Library
- Properties
- MapControl.Caching
- SQLiteCache.UWP
- en-US
- UAP
- 10.0.22000.0
- 10.0.17763.0
- 14
- 512
- {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
-
-
- AnyCPU
- true
- full
- false
- bin\Debug\
- DEBUG;UWP
- prompt
- 4
-
-
- AnyCPU
- none
- true
- bin\Release\
- UWP
- prompt
- 4
-
-
- PackageReference
-
-
-
- SQLiteCache.cs
-
-
- SQLiteCache.WinUI.cs
-
-
-
-
-
-
- 6.2.14
-
-
- 1.0.118
-
-
-
-
- MapControl.snk
-
-
-
-
- {9545f73c-9c35-4cf6-baae-19a0baebd344}
- MapControl.UWP
-
-
-
- 14.0
-
-
- true
-
-
- ..\..\MapControl.snk
-
-
-
\ No newline at end of file
diff --git a/SQLiteCache/WPF/SQLiteCache.WPF.cs b/SQLiteCache/WPF/SQLiteCache.WPF.cs
deleted file mode 100644
index 75a9e5d5..00000000
--- a/SQLiteCache/WPF/SQLiteCache.WPF.cs
+++ /dev/null
@@ -1,215 +0,0 @@
-// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
-// Copyright © 2023 Clemens Fischer
-// Licensed under the Microsoft Public License (Ms-PL)
-
-using System;
-using System.Collections.Generic;
-using System.Data.SQLite;
-using System.Diagnostics;
-using System.Linq;
-using System.Runtime.Caching;
-
-namespace MapControl.Caching
-{
- public partial class SQLiteCache : ObjectCache
- {
- public override string Name => string.Empty;
-
- public override DefaultCacheCapabilities DefaultCacheCapabilities =>
- DefaultCacheCapabilities.AbsoluteExpirations | DefaultCacheCapabilities.SlidingExpirations;
-
- public override object this[string key]
- {
- get => Get(key);
- set => Set(key, value, null);
- }
-
- protected override IEnumerator> GetEnumerator()
- {
- throw new NotSupportedException("SQLiteCache does not support the ability to enumerate items.");
- }
-
- public override CacheEntryChangeMonitor CreateCacheEntryChangeMonitor(IEnumerable keys, string regionName = null)
- {
- throw new NotSupportedException("SQLiteCache does not support the ability to create change monitors.");
- }
-
- public override long GetCount(string regionName = null)
- {
- if (regionName != null)
- {
- throw new NotSupportedException("SQLiteCache does not support named regions.");
- }
-
- try
- {
- using (var command = new SQLiteCommand("select count(*) from items", connection))
- {
- return (long)command.ExecuteScalar();
- }
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"SQLiteCache.GetCount(): {ex.Message}");
- }
-
- return 0;
- }
-
- public override bool Contains(string key, string regionName = null)
- {
- if (regionName != null)
- {
- throw new NotSupportedException("SQLiteCache does not support named regions.");
- }
-
- if (key == null)
- {
- throw new ArgumentNullException(nameof(key));
- }
-
- try
- {
- using (var command = GetItemCommand(key))
- {
- return command.ExecuteReader().Read();
- }
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"SQLiteCache.Contains({key}): {ex.Message}");
- }
-
- return false;
- }
-
- public override object Get(string key, string regionName = null)
- {
- if (regionName != null)
- {
- throw new NotSupportedException("SQLiteCache does not support named regions.");
- }
-
- if (key == null)
- {
- throw new ArgumentNullException(nameof(key));
- }
-
- try
- {
- using (var command = GetItemCommand(key))
- {
- var reader = command.ExecuteReader();
-
- if (reader.Read())
- {
- return Tuple.Create((byte[])reader["buffer"], new DateTime((long)reader["expiration"]));
- }
- }
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"SQLiteCache.Get({key}): {ex.Message}");
- }
-
- return null;
- }
-
- public override CacheItem GetCacheItem(string key, string regionName = null)
- {
- var value = Get(key, regionName);
-
- return value != null ? new CacheItem(key, value) : null;
- }
-
- public override IDictionary GetValues(IEnumerable keys, string regionName = null)
- {
- return keys.ToDictionary(key => key, key => Get(key, regionName));
- }
-
- public override void Set(string key, object value, CacheItemPolicy policy, string regionName = null)
- {
- if (regionName != null)
- {
- throw new NotSupportedException("SQLiteCache does not support named regions.");
- }
-
- if (key == null)
- {
- throw new ArgumentNullException(nameof(key));
- }
-
- if (!(value is Tuple cacheItem))
- {
- throw new ArgumentException("The value argument must be a Tuple.", nameof(value));
- }
-
- try
- {
- using (var command = SetItemCommand(key, cacheItem.Item1, cacheItem.Item2))
- {
- command.ExecuteNonQuery();
- }
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"SQLiteCache.Set({key}): {ex.Message}");
- }
- }
-
- public override void Set(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
- {
- Set(key, value, new CacheItemPolicy { AbsoluteExpiration = absoluteExpiration }, regionName);
- }
-
- public override void Set(CacheItem item, CacheItemPolicy policy)
- {
- Set(item.Key, item.Value, policy, item.RegionName);
- }
-
- public override object AddOrGetExisting(string key, object value, CacheItemPolicy policy, string regionName = null)
- {
- var oldValue = Get(key, regionName);
-
- Set(key, value, policy);
-
- return oldValue;
- }
-
- public override object AddOrGetExisting(string key, object value, DateTimeOffset absoluteExpiration, string regionName = null)
- {
- return AddOrGetExisting(key, value, new CacheItemPolicy { AbsoluteExpiration = absoluteExpiration }, regionName);
- }
-
- public override CacheItem AddOrGetExisting(CacheItem item, CacheItemPolicy policy)
- {
- var oldItem = GetCacheItem(item.Key, item.RegionName);
-
- Set(item, policy);
-
- return oldItem;
- }
-
- public override object Remove(string key, string regionName = null)
- {
- var oldValue = Get(key, regionName);
-
- if (oldValue != null)
- {
- try
- {
- using (var command = RemoveItemCommand(key))
- {
- command.ExecuteNonQuery();
- }
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"SQLiteCache.Remove({key}): {ex.Message}");
- }
- }
-
- return oldValue;
- }
- }
-}
diff --git a/SQLiteCache/WPF/SQLiteCache.WPF.csproj b/SQLiteCache/WPF/SQLiteCache.WPF.csproj
deleted file mode 100644
index 9409abbd..00000000
--- a/SQLiteCache/WPF/SQLiteCache.WPF.csproj
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
- net8.0-windows;net7.0-windows;net6.0-windows;net48;net462
- true
- MapControl.Caching
- XAML Map Control SQLiteCache Library for WPF
- XAML Map Control
- 8.3.0
- Clemens Fischer
- Copyright © 2023 Clemens Fischer
- true
- ..\..\MapControl.snk
- false
- false
- XAML.MapControl.SQLiteCache
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/SQLiteCache/WinUI/SQLiteCache.WinUI.cs b/SQLiteCache/WinUI/SQLiteCache.WinUI.cs
deleted file mode 100644
index 713a1259..00000000
--- a/SQLiteCache/WinUI/SQLiteCache.WinUI.cs
+++ /dev/null
@@ -1,50 +0,0 @@
-// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control
-// Copyright © 2023 Clemens Fischer
-// Licensed under the Microsoft Public License (Ms-PL)
-
-using System;
-using System.Diagnostics;
-using System.Threading.Tasks;
-
-namespace MapControl.Caching
-{
- public partial class SQLiteCache : IImageCache
- {
- public async Task> GetAsync(string key)
- {
- try
- {
- using (var command = GetItemCommand(key))
- {
- var reader = await command.ExecuteReaderAsync();
-
- if (await reader.ReadAsync())
- {
- return Tuple.Create((byte[])reader["buffer"], new DateTime((long)reader["expiration"]));
- }
- }
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"SQLiteCache.GetAsync({key}): {ex.Message}");
- }
-
- return null;
- }
-
- public async Task SetAsync(string key, byte[] buffer, DateTime expiration)
- {
- try
- {
- using (var command = SetItemCommand(key, buffer, expiration))
- {
- await command.ExecuteNonQueryAsync();
- }
- }
- catch (Exception ex)
- {
- Debug.WriteLine($"SQLiteCache.SetAsync({key}): {ex.Message}");
- }
- }
- }
-}
diff --git a/SQLiteCache/WinUI/SQLiteCache.WinUI.csproj b/SQLiteCache/WinUI/SQLiteCache.WinUI.csproj
deleted file mode 100644
index 21afc96b..00000000
--- a/SQLiteCache/WinUI/SQLiteCache.WinUI.csproj
+++ /dev/null
@@ -1,38 +0,0 @@
-
-
- net8.0-windows10.0.17763.0;net7.0-windows10.0.17763.0;net6.0-windows10.0.17763.0
- win10-x86;win10-x64;win10-arm64
- true
- true
- MapControl.Caching
- XAML Map Control SQLiteCache Library for WinUI
- XAML Map Control
- 8.3.0
- Clemens Fischer
- Copyright © 2023 Clemens Fischer
- true
- ..\..\MapControl.snk
- false
- false
- XAML.MapControl.SQLiteCache
- WINUI
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/SampleApps/WpfApplication/MainWindow.xaml.cs b/SampleApps/WpfApplication/MainWindow.xaml.cs
index 04da4435..c166a75a 100644
--- a/SampleApps/WpfApplication/MainWindow.xaml.cs
+++ b/SampleApps/WpfApplication/MainWindow.xaml.cs
@@ -19,7 +19,6 @@ namespace SampleApplication
TileImageLoader.Cache = new ImageFileCache(TileImageLoader.DefaultCacheFolder);
//TileImageLoader.Cache = new FileDbCache(TileImageLoader.DefaultCacheFolder);
//TileImageLoader.Cache = new SQLiteCache(TileImageLoader.DefaultCacheFolder);
- //TileImageLoader.Cache = null;
var bingMapsApiKeyPath = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MapControl", "BingMapsApiKey.txt");
diff --git a/SampleApps/WpfApplication/WpfApplication.csproj b/SampleApps/WpfApplication/WpfApplication.csproj
index 658b33b4..7e890be7 100644
--- a/SampleApps/WpfApplication/WpfApplication.csproj
+++ b/SampleApps/WpfApplication/WpfApplication.csproj
@@ -21,6 +21,8 @@
+
+
@@ -36,6 +38,5 @@
-