diff --git a/MBTiles/Shared/MBTileLayer.cs b/MBTiles/Shared/MBTileLayer.cs
index 394d5f93..4353ff71 100644
--- a/MBTiles/Shared/MBTileLayer.cs
+++ b/MBTiles/Shared/MBTileLayer.cs
@@ -16,7 +16,7 @@ namespace MapControl.MBTiles
///
/// MapTileLayer that uses an MBTiles SQLite Database. See https://wiki.openstreetmap.org/wiki/MBTiles.
///
- public partial class MBTileLayer : MapTileLayer
+ public class MBTileLayer : MapTileLayer
{
private static ILogger logger;
private static ILogger Logger => logger ??= ImageLoader.LoggerFactory?.CreateLogger();
diff --git a/MBTiles/Shared/MBTileSource.cs b/MBTiles/Shared/MBTileSource.cs
index 92af2522..38c210a0 100644
--- a/MBTiles/Shared/MBTileSource.cs
+++ b/MBTiles/Shared/MBTileSource.cs
@@ -15,7 +15,7 @@ using ImageSource = Avalonia.Media.IImage;
namespace MapControl.MBTiles
{
- public sealed partial class MBTileSource : TileSource, IDisposable
+ public sealed class MBTileSource : TileSource, IDisposable
{
private static ILogger logger;
private static ILogger Logger => logger ??= ImageLoader.LoggerFactory?.CreateLogger();
@@ -24,6 +24,8 @@ namespace MapControl.MBTiles
public IDictionary Metadata { get; } = new Dictionary();
+ public override bool Cacheable => false;
+
public async Task OpenAsync(string file)
{
Close();
@@ -85,5 +87,10 @@ namespace MapControl.MBTiles
return image;
}
+
+ public override Uri GetUri(int zoomLevel, int column, int row)
+ {
+ throw new NotSupportedException();
+ }
}
}
diff --git a/MapControl/Avalonia/Tile.Avalonia.cs b/MapControl/Avalonia/ImageTile.Avalonia.cs
similarity index 82%
rename from MapControl/Avalonia/Tile.Avalonia.cs
rename to MapControl/Avalonia/ImageTile.Avalonia.cs
index a7c5f700..7e436993 100644
--- a/MapControl/Avalonia/Tile.Avalonia.cs
+++ b/MapControl/Avalonia/ImageTile.Avalonia.cs
@@ -1,5 +1,6 @@
using Avalonia;
using Avalonia.Animation;
+using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Styling;
using Avalonia.Threading;
@@ -8,9 +9,12 @@ using System.Threading.Tasks;
namespace MapControl
{
- public partial class Tile
+ public class ImageTile(int zoomLevel, int x, int y, int columnCount)
+ : Tile(zoomLevel, x, y, columnCount)
{
- public async Task LoadImageAsync(Func> loadImageFunc)
+ public Image Image { get; } = new Image { Stretch = Stretch.Fill };
+
+ public override async Task LoadImageAsync(Func> loadImageFunc)
{
var image = await loadImageFunc().ConfigureAwait(false);
diff --git a/MapControl/Shared/BoundingBoxTileSource.cs b/MapControl/Shared/BoundingBoxTileSource.cs
index 51ee3ed6..588c862f 100644
--- a/MapControl/Shared/BoundingBoxTileSource.cs
+++ b/MapControl/Shared/BoundingBoxTileSource.cs
@@ -4,7 +4,7 @@ using System.Text;
namespace MapControl
{
- public class BoundingBoxTileSource : TileSource
+ public class BoundingBoxTileSource : UriTileSource
{
public override Uri GetUri(int zoomLevel, int column, int row)
{
diff --git a/MapControl/Shared/TileCollection.cs b/MapControl/Shared/ImageTileList.cs
similarity index 72%
rename from MapControl/Shared/TileCollection.cs
rename to MapControl/Shared/ImageTileList.cs
index 58257e99..bf058f18 100644
--- a/MapControl/Shared/TileCollection.cs
+++ b/MapControl/Shared/ImageTileList.cs
@@ -3,12 +3,12 @@ using System.Linq;
namespace MapControl
{
- public partial class TileCollection : List
+ public partial class ImageTileList : List
{
///
- /// Adds existing Tiles from the source collection or newly created Tiles to fill the specified tile matrix.
+ /// Adds existing ImageTile from the source collection or newly created ImageTile to fill the specified tile matrix.
///
- public void FillMatrix(TileCollection source, int zoomLevel, int xMin, int yMin, int xMax, int yMax, int columnCount)
+ public void FillMatrix(ImageTileList source, int zoomLevel, int xMin, int yMin, int xMax, int yMax, int columnCount)
{
for (var y = yMin; y <= yMax; y++)
{
@@ -18,7 +18,7 @@ namespace MapControl
if (tile == null)
{
- tile = new Tile(zoomLevel, x, y, columnCount);
+ tile = new ImageTile(zoomLevel, x, y, columnCount);
var equivalentTile = source.FirstOrDefault(
t => t.Image.Source != null && t.ZoomLevel == tile.ZoomLevel && t.Column == tile.Column && t.Row == tile.Row);
diff --git a/MapControl/Shared/MapTileLayer.cs b/MapControl/Shared/MapTileLayer.cs
index f2986741..4ec4391f 100644
--- a/MapControl/Shared/MapTileLayer.cs
+++ b/MapControl/Shared/MapTileLayer.cs
@@ -43,7 +43,7 @@ namespace MapControl
///
public static MapTileLayer OpenStreetMapTileLayer => new()
{
- TileSource = new TileSource { UriTemplate = "https://tile.openstreetmap.org/{z}/{x}/{y}.png" },
+ TileSource = TileSource.Parse("https://tile.openstreetmap.org/{z}/{x}/{y}.png"),
SourceName = "OpenStreetMap",
Description = "© [OpenStreetMap Contributors](http://www.openstreetmap.org/copyright)"
};
@@ -52,7 +52,7 @@ namespace MapControl
public TileMatrix TileMatrix { get; private set; }
- public TileCollection Tiles { get; private set; } = [];
+ public ImageTileList Tiles { get; private set; } = [];
///
/// Minimum zoom level supported by the MapTileLayer. Default value is 0.
@@ -178,7 +178,7 @@ namespace MapControl
private void UpdateTiles(bool reset)
{
- var tiles = new TileCollection();
+ var tiles = new ImageTileList();
if (TileSource != null && TileMatrix != null)
{
diff --git a/MapControl/Shared/Tile.cs b/MapControl/Shared/Tile.cs
index 411b4ee0..b4b96ef6 100644
--- a/MapControl/Shared/Tile.cs
+++ b/MapControl/Shared/Tile.cs
@@ -1,20 +1,18 @@
-#if WPF
-using System.Windows.Controls;
+using System;
+using System.Threading.Tasks;
+#if WPF
using System.Windows.Media;
#elif UWP
-using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
#elif WINUI
-using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
#elif AVALONIA
-using Avalonia.Controls;
-using Avalonia.Media;
+using ImageSource = Avalonia.Media.IImage;
#endif
namespace MapControl
{
- public partial class Tile(int zoomLevel, int x, int y, int columnCount) : ITile
+ public abstract class Tile(int zoomLevel, int x, int y, int columnCount)
{
public int ZoomLevel { get; } = zoomLevel;
public int X { get; } = x;
@@ -22,6 +20,10 @@ namespace MapControl
public int Column { get; } = ((x % columnCount) + columnCount) % columnCount;
public int Row => Y;
public bool IsPending { get; set; } = true;
- public Image Image { get; } = new Image { Stretch = Stretch.Fill };
+
+ ///
+ /// Runs a tile image download Task and marshals the result to the UI thread.
+ ///
+ public abstract Task LoadImageAsync(Func> loadImageFunc);
}
}
diff --git a/MapControl/Shared/TileImageLoader.cs b/MapControl/Shared/TileImageLoader.cs
index c2559da4..d83162e3 100644
--- a/MapControl/Shared/TileImageLoader.cs
+++ b/MapControl/Shared/TileImageLoader.cs
@@ -7,61 +7,16 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
-#if WPF
-using System.Windows.Media;
-#elif UWP
-using Windows.UI.Xaml.Media;
-#elif WINUI
-using Microsoft.UI.Xaml.Media;
-#elif AVALONIA
-using ImageSource = Avalonia.Media.IImage;
-#endif
namespace MapControl
{
- public interface ITile
- {
- int ZoomLevel { get; }
- int Column { get; }
- int Row { get; }
- bool IsPending { get; set; }
-
- ///
- /// Runs a tile image download Task and marshals the result to the UI thread.
- ///
- Task LoadImageAsync(Func> loadImageFunc);
- }
-
- public interface ITileSource
- {
- ///
- /// Indicates whether tile images from this source should be cached.
- ///
- bool Cacheable { get; }
-
- ///
- /// Gets the image Uri for the specified zoom level and tile indices.
- ///
- Uri GetUri(int zoomLevel, int column, int row);
-
- ///
- /// Loads a tile image whithout caching.
- ///
- Task LoadImageAsync(int zoomLevel, int column, int row);
-
- ///
- /// Loads a cacheable tile image from an encoded frame buffer.
- ///
- Task LoadImageAsync(byte[] buffer);
- }
-
public interface ITileImageLoader
{
///
/// Loads all pending tiles from the tiles collection.
/// Tile image caching is enabled when tileSource.UriFormat starts with "http" and cacheName is a non-empty string.
///
- void BeginLoadTiles(IEnumerable tiles, ITileSource tileSource, string cacheName, IProgress progress);
+ void BeginLoadTiles(IEnumerable tiles, TileSource tileSource, string cacheName, IProgress progress);
///
/// Cancels a potentially ongoing tile loading task.
@@ -115,11 +70,11 @@ namespace MapControl
///
public static int MaxLoadTasks { get; set; } = 4;
- private readonly Queue tileQueue = new();
+ private readonly Queue tileQueue = new();
private int tileCount;
private int taskCount;
- public void BeginLoadTiles(IEnumerable tiles, ITileSource tileSource, string cacheName, IProgress progress)
+ public void BeginLoadTiles(IEnumerable tiles, TileSource tileSource, string cacheName, IProgress progress)
{
if (Cache == null || !tileSource.Cacheable)
{
@@ -158,9 +113,9 @@ namespace MapControl
}
}
- private async Task LoadTilesFromQueue(ITileSource tileSource, string cacheName, IProgress progress)
+ private async Task LoadTilesFromQueue(TileSource tileSource, string cacheName, IProgress progress)
{
- bool TryDequeueTile(out ITile tile)
+ bool TryDequeueTile(out Tile tile)
{
lock (tileQueue)
{
@@ -178,7 +133,7 @@ namespace MapControl
return false;
}
- while (TryDequeueTile(out ITile tile))
+ while (TryDequeueTile(out Tile tile))
{
tile.IsPending = false;
@@ -218,7 +173,7 @@ namespace MapControl
}
}
- private static async Task LoadCachedBuffer(ITile tile, Uri uri, string cacheName)
+ private static async Task LoadCachedBuffer(Tile tile, Uri uri, string cacheName)
{
var extension = Path.GetExtension(uri.LocalPath).ToLower();
diff --git a/MapControl/Shared/TilePyramidLayer.cs b/MapControl/Shared/TilePyramidLayer.cs
index f8216a80..3db0876e 100644
--- a/MapControl/Shared/TilePyramidLayer.cs
+++ b/MapControl/Shared/TilePyramidLayer.cs
@@ -192,7 +192,7 @@ namespace MapControl
protected bool IsBaseMapLayer => parentMap != null && parentMap.Children.Count > 0 && parentMap.Children[0] == this;
- protected void BeginLoadTiles(IEnumerable tiles, string cacheName)
+ protected void BeginLoadTiles(IEnumerable tiles, string cacheName)
{
if (TileSource != null && tiles != null && tiles.Any(tile => tile.IsPending))
{
diff --git a/MapControl/Shared/TileSource.cs b/MapControl/Shared/TileSource.cs
index 4c73c62f..667fdd32 100644
--- a/MapControl/Shared/TileSource.cs
+++ b/MapControl/Shared/TileSource.cs
@@ -21,7 +21,41 @@ namespace MapControl
#else
[System.ComponentModel.TypeConverter(typeof(TileSourceConverter))]
#endif
- public class TileSource : ITileSource
+ public abstract class TileSource
+ {
+ ///
+ /// Indicates whether tile images from this source should be cached.
+ ///
+ public abstract bool Cacheable { get; }
+
+ ///
+ /// Gets the image Uri for the specified zoom level and tile indices.
+ ///
+ public abstract Uri GetUri(int zoomLevel, int column, int row);
+
+ ///
+ /// Loads a tile image whithout caching.
+ ///
+ public abstract Task LoadImageAsync(int zoomLevel, int column, int row);
+
+ ///
+ /// Loads a cacheable tile image from an encoded frame buffer.
+ ///
+ public virtual Task LoadImageAsync(byte[] buffer)
+ {
+ return ImageLoader.LoadImageAsync(buffer);
+ }
+
+ ///
+ /// Creates a TileSource instance from an Uri template string.
+ ///
+ public static TileSource Parse(string uriTemplate)
+ {
+ return new UriTileSource { UriTemplate = uriTemplate };
+ }
+ }
+
+ public class UriTileSource : TileSource
{
private string uriTemplate;
@@ -44,9 +78,9 @@ namespace MapControl
public string[] Subdomains { get; set; }
- public bool Cacheable => UriTemplate != null && UriTemplate.StartsWith("http");
+ public override bool Cacheable => UriTemplate != null && UriTemplate.StartsWith("http");
- public virtual Uri GetUri(int zoomLevel, int column, int row)
+ public override Uri GetUri(int zoomLevel, int column, int row)
{
Uri uri = null;
@@ -69,33 +103,20 @@ namespace MapControl
return uri;
}
- public virtual Task LoadImageAsync(int zoomLevel, int column, int row)
+ public override Task LoadImageAsync(int zoomLevel, int column, int row)
{
var uri = GetUri(zoomLevel, column, row);
return uri != null ? ImageLoader.LoadImageAsync(uri) : Task.FromResult((ImageSource)null);
}
- public virtual Task LoadImageAsync(byte[] buffer)
- {
- return ImageLoader.LoadImageAsync(buffer);
- }
-
public override string ToString()
{
return UriTemplate;
}
-
- ///
- /// Creates a TileSource instance from an Uri template string.
- ///
- public static TileSource Parse(string uriTemplate)
- {
- return new TileSource { UriTemplate = uriTemplate };
- }
}
- public class TmsTileSource : TileSource
+ public class TmsTileSource : UriTileSource
{
public override Uri GetUri(int zoomLevel, int column, int row)
{
diff --git a/MapControl/Shared/WmtsTileMatrixLayer.cs b/MapControl/Shared/WmtsTileMatrixLayer.cs
index bb5d569f..f1566d6c 100644
--- a/MapControl/Shared/WmtsTileMatrixLayer.cs
+++ b/MapControl/Shared/WmtsTileMatrixLayer.cs
@@ -35,7 +35,7 @@ namespace MapControl
public TileMatrix TileMatrix { get; private set; }
- public TileCollection Tiles { get; private set; } = [];
+ public ImageTileList Tiles { get; private set; } = [];
public void UpdateRenderTransform(ViewTransform viewTransform)
{
@@ -85,7 +85,7 @@ namespace MapControl
TileMatrix = new TileMatrix(TileMatrix.ZoomLevel, xMin, yMin, xMax, yMax);
- var tiles = new TileCollection();
+ var tiles = new ImageTileList();
tiles.FillMatrix(Tiles, TileMatrix.ZoomLevel, xMin, yMin, xMax, yMax, WmtsTileMatrix.MatrixWidth);
Tiles = tiles;
diff --git a/MapControl/Shared/WmtsTileSource.cs b/MapControl/Shared/WmtsTileSource.cs
index 0bebd836..7810e507 100644
--- a/MapControl/Shared/WmtsTileSource.cs
+++ b/MapControl/Shared/WmtsTileSource.cs
@@ -3,7 +3,7 @@ using System.Text;
namespace MapControl
{
- public class WmtsTileSource : TileSource
+ public class WmtsTileSource : UriTileSource
{
public WmtsTileMatrixSet TileMatrixSet { get; set; }
diff --git a/MapControl/WPF/Tile.WPF.cs b/MapControl/WPF/ImageTile.WPF.cs
similarity index 87%
rename from MapControl/WPF/Tile.WPF.cs
rename to MapControl/WPF/ImageTile.WPF.cs
index 5bb491fa..251d01ac 100644
--- a/MapControl/WPF/Tile.WPF.cs
+++ b/MapControl/WPF/ImageTile.WPF.cs
@@ -8,9 +8,12 @@ using System.Windows.Media.Imaging;
namespace MapControl
{
- public partial class Tile
+ public class ImageTile(int zoomLevel, int x, int y, int columnCount)
+ : Tile(zoomLevel, x, y, columnCount)
{
- public async Task LoadImageAsync(Func> loadImageFunc)
+ public Image Image { get; } = new Image { Stretch = Stretch.Fill };
+
+ public override async Task LoadImageAsync(Func> loadImageFunc)
{
var image = await loadImageFunc().ConfigureAwait(false);
diff --git a/MapControl/WinUI/Tile.WinUI.cs b/MapControl/WinUI/ImageTile.WinUI.cs
similarity index 89%
rename from MapControl/WinUI/Tile.WinUI.cs
rename to MapControl/WinUI/ImageTile.WinUI.cs
index ffc56d66..fa218e1b 100644
--- a/MapControl/WinUI/Tile.WinUI.cs
+++ b/MapControl/WinUI/ImageTile.WinUI.cs
@@ -3,12 +3,14 @@ using System.Threading.Tasks;
#if UWP
using Windows.UI.Core;
using Windows.UI.Xaml;
+using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Animation;
using Windows.UI.Xaml.Media.Imaging;
#else
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Animation;
using Microsoft.UI.Xaml.Media.Imaging;
@@ -16,9 +18,12 @@ using Microsoft.UI.Xaml.Media.Imaging;
namespace MapControl
{
- public partial class Tile
+ public class ImageTile(int zoomLevel, int x, int y, int columnCount)
+ : Tile(zoomLevel, x, y, columnCount)
{
- public async Task LoadImageAsync(Func> loadImageFunc)
+ public Image Image { get; } = new Image { Stretch = Stretch.Fill };
+
+ public override async Task LoadImageAsync(Func> loadImageFunc)
{
var tcs = new TaskCompletionSource