.NET 9, including UWP

This commit is contained in:
ClemensFischer 2025-09-14 21:02:21 +02:00
parent 3526438f58
commit cf0f4645d4
56 changed files with 484 additions and 1206 deletions

View file

@ -63,7 +63,7 @@ namespace MapControl
private static string QueryString(ushort tag) => $"/ifd/{{ushort={tag}}}";
private static ILogger logger;
private static ILogger Logger => logger ?? (logger = ImageLoader.LoggerFactory?.CreateLogger(nameof(GeoImage)));
private static ILogger Logger => logger ??= ImageLoader.LoggerFactory?.CreateLogger<GroundOverlay>();
public static readonly DependencyProperty SourcePathProperty =
DependencyPropertyHelper.RegisterAttached<string>("SourcePath", typeof(GeoImage), null,
@ -158,33 +158,32 @@ namespace MapControl
private static async Task<Matrix> ReadWorldFileMatrix(string worldFilePath)
{
using (var fileStream = File.OpenRead(worldFilePath))
using (var streamReader = new StreamReader(fileStream))
using var fileStream = File.OpenRead(worldFilePath);
using var streamReader = new StreamReader(fileStream);
var parameters = new double[6];
var index = 0;
string line;
while (index < 6 &&
(line = await streamReader.ReadLineAsync()) != null &&
double.TryParse(line, NumberStyles.Float, CultureInfo.InvariantCulture, out double parameter))
{
var parameters = new double[6];
var index = 0;
string line;
while (index < 6 &&
(line = await streamReader.ReadLineAsync()) != null &&
double.TryParse(line, NumberStyles.Float, CultureInfo.InvariantCulture, out double parameter))
{
parameters[index++] = parameter;
}
if (index != 6)
{
throw new ArgumentException($"Insufficient number of parameters in world file {worldFilePath}.");
}
return new Matrix(
parameters[0], // line 1: A or M11
parameters[1], // line 2: D or M12
parameters[2], // line 3: B or M21
parameters[3], // line 4: E or M22
parameters[4], // line 5: C or OffsetX
parameters[5]); // line 6: F or OffsetY
parameters[index++] = parameter;
}
if (index != 6)
{
throw new ArgumentException($"Insufficient number of parameters in world file {worldFilePath}.");
}
return new Matrix(
parameters[0], // line 1: A or M11
parameters[1], // line 2: D or M12
parameters[2], // line 3: B or M21
parameters[3], // line 4: E or M22
parameters[4], // line 5: C or OffsetX
parameters[5]); // line 6: F or OffsetY
}
private static MapProjection GetProjection(short[] geoKeyDirectory)

View file

@ -52,23 +52,22 @@ namespace MapControl
if (entry != null)
{
using (var memoryStream = new MemoryStream((int)entry.Length))
using var memoryStream = new MemoryStream((int)entry.Length);
using (var zipStream = entry.Open())
{
using (var zipStream = entry.Open())
{
zipStream.CopyTo(memoryStream); // can't use CopyToAsync with ZipArchive
}
memoryStream.Seek(0, SeekOrigin.Begin);
Image.Source = await ImageLoader.LoadImageAsync(memoryStream);
zipStream.CopyTo(memoryStream); // can't use CopyToAsync with ZipArchive
}
memoryStream.Seek(0, SeekOrigin.Begin);
Image.Source = await ImageLoader.LoadImageAsync(memoryStream);
}
}
}
private static ILogger logger;
private static ILogger Logger => logger ?? (logger = ImageLoader.LoggerFactory?.CreateLogger<GroundOverlay>());
private static ILogger Logger => logger ??= ImageLoader.LoggerFactory?.CreateLogger<GroundOverlay>();
public static readonly DependencyProperty SourcePathProperty =
DependencyPropertyHelper.Register<GroundOverlay, string>(nameof(SourcePath), null,
@ -127,20 +126,19 @@ namespace MapControl
private static async Task<List<ImageOverlay>> LoadImageOverlaysFromArchive(string archiveFilePath)
{
using (var archive = ZipFile.OpenRead(archiveFilePath))
using var archive = ZipFile.OpenRead(archiveFilePath);
var docEntry = archive.GetEntry("doc.kml") ??
archive.Entries.FirstOrDefault(e => e.Name.EndsWith(".kml")) ??
throw new ArgumentException($"No KML entry found in {archiveFilePath}.");
XDocument document;
using (var docStream = docEntry.Open())
{
var docEntry = archive.GetEntry("doc.kml") ??
archive.Entries.FirstOrDefault(e => e.Name.EndsWith(".kml")) ??
throw new ArgumentException($"No KML entry found in {archiveFilePath}.");
XDocument document;
using (var docStream = docEntry.Open())
{
document = await LoadXDocument(docStream);
}
return await LoadImageOverlays(document, imageOverlay => imageOverlay.LoadImage(archive));
document = await LoadXDocument(docStream);
}
return await LoadImageOverlays(document, imageOverlay => imageOverlay.LoadImage(archive));
}
private static async Task<List<ImageOverlay>> LoadImageOverlaysFromFile(string docFilePath)

View file

@ -326,34 +326,30 @@ namespace MapControl.Caching
private static byte[] ReadAllBytes(FileInfo file)
{
using (var stream = file.OpenRead())
using var stream = file.OpenRead();
var buffer = new byte[stream.Length];
var offset = 0;
while (offset < buffer.Length)
{
var buffer = new byte[stream.Length];
var offset = 0;
while (offset < buffer.Length)
{
offset += stream.Read(buffer, offset, buffer.Length - offset);
}
return buffer;
offset += stream.Read(buffer, offset, buffer.Length - offset);
}
return buffer;
}
private static async Task<byte[]> ReadAllBytes(FileInfo file, CancellationToken token)
{
using (var stream = file.OpenRead())
using var stream = file.OpenRead();
var buffer = new byte[stream.Length];
var offset = 0;
while (offset < buffer.Length)
{
var buffer = new byte[stream.Length];
var offset = 0;
while (offset < buffer.Length)
{
offset += await stream.ReadAsync(buffer, offset, buffer.Length - offset, token).ConfigureAwait(false);
}
return buffer;
offset += await stream.ReadAsync(buffer, offset, buffer.Length - offset, token).ConfigureAwait(false);
}
return buffer;
}
private static void SetExpiration(FileInfo file, DistributedCacheEntryOptions options)

View file

@ -16,7 +16,7 @@ namespace MapControl
public static partial class ImageLoader
{
private static ILogger logger;
private static ILogger Logger => logger ?? (logger = LoggerFactory?.CreateLogger(typeof(ImageLoader)));
private static ILogger Logger => logger ??= ImageLoader.LoggerFactory?.CreateLogger<GroundOverlay>();
public static ILoggerFactory LoggerFactory { get; set; }
@ -33,10 +33,9 @@ namespace MapControl
public static async Task<ImageSource> LoadImageAsync(byte[] buffer)
{
using (var stream = new MemoryStream(buffer))
{
return await LoadImageAsync(stream);
}
using var stream = new MemoryStream(buffer);
return await LoadImageAsync(stream);
}
public static async Task<ImageSource> LoadImageAsync(Uri uri, IProgress<double> progress = null)
@ -84,25 +83,24 @@ namespace MapControl
{
var completionOptions = progress != null ? HttpCompletionOption.ResponseHeadersRead : HttpCompletionOption.ResponseContentRead;
using (var responseMessage = await HttpClient.GetAsync(uri, completionOptions).ConfigureAwait(false))
{
if (responseMessage.IsSuccessStatusCode)
{
if (progress != null && responseMessage.Content.Headers.ContentLength.HasValue)
{
buffer = await ReadAsByteArray(responseMessage.Content, progress).ConfigureAwait(false);
}
else
{
buffer = await responseMessage.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
}
using var responseMessage = await HttpClient.GetAsync(uri, completionOptions).ConfigureAwait(false);
maxAge = responseMessage.Headers.CacheControl?.MaxAge;
if (responseMessage.IsSuccessStatusCode)
{
if (progress != null && responseMessage.Content.Headers.ContentLength.HasValue)
{
buffer = await ReadAsByteArray(responseMessage.Content, progress).ConfigureAwait(false);
}
else
{
Logger?.LogWarning("{status} ({reason}) from {uri}", (int)responseMessage.StatusCode, responseMessage.ReasonPhrase, uri);
buffer = await responseMessage.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
}
maxAge = responseMessage.Headers.CacheControl?.MaxAge;
}
else
{
Logger?.LogWarning("{status} ({reason}) from {uri}", (int)responseMessage.StatusCode, responseMessage.ReasonPhrase, uri);
}
}
catch (TaskCanceledException)

View file

@ -23,7 +23,7 @@ namespace MapControl
public class TileImageLoader : ITileImageLoader
{
private static ILogger logger;
private static ILogger Logger => logger ?? (logger = ImageLoader.LoggerFactory?.CreateLogger<TileImageLoader>());
private static ILogger Logger => logger ??= ImageLoader.LoggerFactory?.CreateLogger<GroundOverlay>();
/// <summary>
/// Default folder path where a persistent cache implementation may save data, i.e. "C:\ProgramData\MapControl\TileCache".

View file

@ -26,7 +26,7 @@ namespace MapControl
public class WmsImageLayer : MapImageLayer
{
private static ILogger logger;
private static ILogger Logger => logger ?? (logger = ImageLoader.LoggerFactory?.CreateLogger<WmsImageLayer>());
private static ILogger Logger => logger ??= ImageLoader.LoggerFactory?.CreateLogger<GroundOverlay>();
public static readonly DependencyProperty ServiceUriProperty =
DependencyPropertyHelper.Register<WmsImageLayer, Uri>(nameof(ServiceUri), null,
@ -112,10 +112,9 @@ namespace MapControl
{
try
{
using (var stream = await ImageLoader.HttpClient.GetStreamAsync(uri))
{
element = XDocument.Load(stream).Root;
}
using var stream = await ImageLoader.HttpClient.GetStreamAsync(uri);
element = XDocument.Load(stream).Root;
}
catch (Exception ex)
{

View file

@ -31,10 +31,9 @@ namespace MapControl
if (capabilitiesUri.IsAbsoluteUri && (capabilitiesUri.Scheme == "http" || capabilitiesUri.Scheme == "https"))
{
using (var stream = await ImageLoader.HttpClient.GetStreamAsync(capabilitiesUri))
{
capabilities = ReadCapabilities(XDocument.Load(stream).Root, layer, capabilitiesUri.ToString());
}
using var stream = await ImageLoader.HttpClient.GetStreamAsync(capabilitiesUri);
capabilities = ReadCapabilities(XDocument.Load(stream).Root, layer, capabilitiesUri.ToString());
}
else
{
@ -46,12 +45,8 @@ namespace MapControl
public static WmtsCapabilities ReadCapabilities(XElement capabilitiesElement, string layer, string capabilitiesUrl)
{
var contentsElement = capabilitiesElement.Element(wmts + "Contents");
if (contentsElement == null)
{
throw new ArgumentException("Contents element not found.");
}
var contentsElement = capabilitiesElement.Element(wmts + "Contents")
?? throw new ArgumentException("Contents element not found.");
XElement layerElement;
@ -102,12 +97,8 @@ namespace MapControl
{
var tileMatrixSetElement = contentsElement
.Elements(wmts + "TileMatrixSet")
.FirstOrDefault(s => s.Element(ows + "Identifier")?.Value == tileMatrixSetId);
if (tileMatrixSetElement == null)
{
throw new ArgumentException($"Linked TileMatrixSet element not found in Layer \"{layer}\".");
}
.FirstOrDefault(s => s.Element(ows + "Identifier")?.Value == tileMatrixSetId)
?? throw new ArgumentException($"Linked TileMatrixSet element not found in Layer \"{layer}\".");
tileMatrixSets.Add(ReadTileMatrixSet(tileMatrixSetElement));
}
@ -134,7 +125,7 @@ namespace MapControl
.ToLookup(r => r.Attribute("format").Value,
r => r.Attribute("template").Value);
if (resourceUrls.Any())
if (resourceUrls.Count != 0)
{
var urlTemplates = resourceUrls.Contains(formatPng) ? resourceUrls[formatPng]
: resourceUrls.Contains(formatJpg) ? resourceUrls[formatJpg]

View file

@ -23,7 +23,7 @@ namespace MapControl
public class WmtsTileLayer : MapTileLayerBase
{
private static ILogger logger;
private static ILogger Logger => logger ?? (logger = ImageLoader.LoggerFactory?.CreateLogger<WmtsTileLayer>());
private static ILogger Logger => logger ??= ImageLoader.LoggerFactory?.CreateLogger<GroundOverlay>();
public static readonly DependencyProperty CapabilitiesUriProperty =
DependencyPropertyHelper.Register<WmtsTileLayer, Uri>(nameof(CapabilitiesUri), null,

View file

@ -6,7 +6,7 @@ namespace MapControl
{
public WmtsTileMatrixSet TileMatrixSet { get; set; }
public override Uri GetUri(int column, int row, int zoomLevel)
public override Uri GetUri(int zoomLevel, int column, int row)
{
Uri uri = null;