Version 7.3. Added tile and map image progress reporting.

This commit is contained in:
Clemens 2022-08-05 18:54:19 +02:00
parent b423cc2d36
commit 3119c0fc9b
32 changed files with 252 additions and 100 deletions

View file

@ -6,8 +6,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2022 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("7.2.1")]
[assembly: AssemblyFileVersion("7.2.1")]
[assembly: AssemblyVersion("7.3.0")]
[assembly: AssemblyFileVersion("7.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -5,7 +5,7 @@
<RootNamespace>MapControl.Caching</RootNamespace>
<AssemblyTitle>XAML Map Control FileDbCache Library for WPF</AssemblyTitle>
<Product>XAML Map Control</Product>
<Version>7.2.1</Version>
<Version>7.3.0</Version>
<Authors>Clemens Fischer</Authors>
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
<SignAssembly>true</SignAssembly>

View file

@ -7,7 +7,7 @@
<RootNamespace>MapControl.Caching</RootNamespace>
<AssemblyTitle>XAML Map Control FileDbCache Library for WinUI</AssemblyTitle>
<Product>XAML Map Control</Product>
<Version>7.2.1</Version>
<Version>7.3.0</Version>
<Authors>Clemens Fischer</Authors>
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
<SignAssembly>true</SignAssembly>

View file

@ -6,8 +6,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2022 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("7.2.1")]
[assembly: AssemblyFileVersion("7.2.1")]
[assembly: AssemblyVersion("7.3.0")]
[assembly: AssemblyFileVersion("7.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -5,7 +5,7 @@
<RootNamespace>MapControl.MBTiles</RootNamespace>
<AssemblyTitle>XAML Map Control MBTiles Library for WPF</AssemblyTitle>
<Product>XAML Map Control</Product>
<Version>7.2.1</Version>
<Version>7.3.0</Version>
<Authors>Clemens Fischer</Authors>
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
<SignAssembly>true</SignAssembly>

View file

@ -7,7 +7,7 @@
<RootNamespace>MapControl.MBTiles</RootNamespace>
<AssemblyTitle>XAML Map Control MBTiles Library for WinUI</AssemblyTitle>
<Product>XAML Map Control</Product>
<Version>7.2.1</Version>
<Version>7.3.0</Version>
<Authors>Clemens Fischer</Authors>
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
<SignAssembly>true</SignAssembly>

View file

@ -29,7 +29,7 @@ namespace MapControl
public static HttpClient HttpClient { get; set; } = new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
public static async Task<ImageSource> LoadImageAsync(Uri uri)
public static async Task<ImageSource> LoadImageAsync(Uri uri, IProgress<double> progress = null)
{
ImageSource image = null;
@ -41,7 +41,7 @@ namespace MapControl
}
else if (uri.Scheme == "http" || uri.Scheme == "https")
{
var response = await GetHttpResponseAsync(uri);
var response = await GetHttpResponseAsync(uri, progress);
if (response != null && response.Buffer != null)
{
@ -73,10 +73,12 @@ namespace MapControl
}
}
internal static async Task<HttpResponse> GetHttpResponseAsync(Uri uri)
internal static async Task<HttpResponse> GetHttpResponseAsync(Uri uri, IProgress<double> progress = null)
{
HttpResponse response = null;
progress?.Report(0d);
try
{
using (var responseMessage = await HttpClient.GetAsync(uri, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false))
@ -85,10 +87,12 @@ namespace MapControl
{
byte[] buffer = null;
// check for possibly unavailable Bing Maps tile
//
if (!responseMessage.Headers.TryGetValues("X-VE-Tile-Info", out IEnumerable<string> tileInfo) ||
!tileInfo.Contains("no-tile"))
{
buffer = await responseMessage.Content.ReadAsByteArrayAsync().ConfigureAwait(false);
buffer = await ReadAsByteArrayAsync(responseMessage.Content, progress).ConfigureAwait(false);
}
response = new HttpResponse(buffer, responseMessage.Headers.CacheControl?.MaxAge);
@ -104,7 +108,39 @@ namespace MapControl
Debug.WriteLine($"ImageLoader: {uri}: {ex.Message}");
}
progress?.Report(1d);
return response;
}
private static async Task<byte[]> ReadAsByteArrayAsync(HttpContent content, IProgress<double> progress)
{
if (progress == null || !content.Headers.ContentLength.HasValue)
{
return await content.ReadAsByteArrayAsync().ConfigureAwait(false);
}
var length = (int)content.Headers.ContentLength.Value;
var buffer = new byte[length];
using (var stream = await content.ReadAsStreamAsync().ConfigureAwait(false))
{
int offset = 0;
int read;
while (offset < length &&
(read = await stream.ReadAsync(buffer, offset, length - offset).ConfigureAwait(false)) > 0)
{
offset += read;
if (offset < length) // 1.0 reported by caller
{
progress.Report((double)offset / length);
}
}
}
return buffer;
}
}
}

View file

@ -54,11 +54,17 @@ namespace MapControl
public static readonly DependencyProperty MapForegroundProperty = DependencyProperty.Register(
nameof(MapForeground), typeof(Brush), typeof(MapImageLayer), new PropertyMetadata(null));
public static readonly DependencyProperty LoadingProgressProperty = DependencyProperty.Register(
nameof(LoadingProgress), typeof(double), typeof(MapImageLayer), new PropertyMetadata(1d));
private readonly Progress<double> imageProgress;
private readonly DispatcherTimer updateTimer;
private bool updateInProgress;
public MapImageLayer()
{
imageProgress = new Progress<double>(p => LoadingProgress = p);
updateTimer = this.CreateTimer(UpdateInterval);
updateTimer.Tick += async (s, e) => await UpdateImageAsync();
}
@ -119,13 +125,20 @@ namespace MapControl
set { SetValue(MapForegroundProperty, value); }
}
/// <summary>
/// Gets the progress of the ImageLoader as a double value between 0 and 1.
/// </summary>
public double LoadingProgress
{
get { return (double)GetValue(LoadingProgressProperty); }
private set { SetValue(LoadingProgressProperty, value); }
}
/// <summary>
/// The current BoundingBox
/// </summary>
public BoundingBox BoundingBox { get; private set; }
protected abstract Task<ImageSource> GetImageAsync();
protected override void SetParentMap(MapBase map)
{
if (map == null)
@ -165,38 +178,43 @@ namespace MapControl
protected async Task UpdateImageAsync()
{
updateTimer.Stop();
if (updateInProgress)
if (updateInProgress) // update image on next tick
{
updateTimer.Run(); // update image on next timer tick
updateTimer.Run(); // start timer if not running
}
else if (ParentMap != null && ParentMap.RenderSize.Width > 0 && ParentMap.RenderSize.Height > 0)
else
{
updateInProgress = true;
updateTimer.Stop();
UpdateBoundingBox();
ImageSource image = null;
if (BoundingBox != null)
if (ParentMap != null && ParentMap.RenderSize.Width > 0 && ParentMap.RenderSize.Height > 0)
{
try
updateInProgress = true;
UpdateBoundingBox();
ImageSource image = null;
if (BoundingBox != null)
{
image = await GetImageAsync();
}
catch (Exception ex)
{
Debug.WriteLine($"MapImageLayer: {ex.Message}");
try
{
image = await GetImageAsync(imageProgress);
}
catch (Exception ex)
{
Debug.WriteLine($"MapImageLayer: {ex.Message}");
}
}
SwapImages(image);
updateInProgress = false;
}
SwapImages(image);
updateInProgress = false;
}
}
protected abstract Task<ImageSource> GetImageAsync(IProgress<double> progress);
private void UpdateBoundingBox()
{
var width = ParentMap.RenderSize.Width * RelativeImageSize;

View file

@ -25,6 +25,8 @@ namespace MapControl
{
public interface ITileImageLoader
{
IProgress<double> Progress { get; set; }
TileSource TileSource { get; }
Task LoadTiles(IEnumerable<Tile> tiles, TileSource tileSource, string cacheName);
@ -58,13 +60,19 @@ namespace MapControl
public static readonly DependencyProperty MapForegroundProperty = DependencyProperty.Register(
nameof(MapForeground), typeof(Brush), typeof(MapTileLayerBase), new PropertyMetadata(null));
public static readonly DependencyProperty LoadingProgressProperty = DependencyProperty.Register(
nameof(LoadingProgress), typeof(double), typeof(MapTileLayerBase), new PropertyMetadata(1d,
(o, e) => { System.Diagnostics.Debug.WriteLine("LoadingProgress = {0:P0}", e.NewValue); }));
private readonly DispatcherTimer updateTimer;
private MapBase parentMap;
protected MapTileLayerBase(ITileImageLoader tileImageLoader)
{
RenderTransform = new MatrixTransform();
TileImageLoader = tileImageLoader;
TileImageLoader.Progress = new Progress<double>(p => LoadingProgress = p);
updateTimer = this.CreateTimer(UpdateInterval);
updateTimer.Tick += async (s, e) => await Update();
@ -149,6 +157,15 @@ namespace MapControl
set { SetValue(MapForegroundProperty, value); }
}
/// <summary>
/// Gets the progress of the TileImageLoader as a double value between 0 and 1.
/// </summary>
public double LoadingProgress
{
get { return (double)GetValue(LoadingProgressProperty); }
private set { SetValue(LoadingProgressProperty, value); }
}
public MapBase ParentMap
{
get { return parentMap; }

View file

@ -9,6 +9,7 @@ using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace MapControl
@ -18,6 +19,35 @@ namespace MapControl
/// </summary>
public partial class TileImageLoader : ITileImageLoader
{
private class TileQueue : ConcurrentStack<Tile>
{
public TileQueue(IEnumerable<Tile> tiles)
: base(tiles.Where(tile => tile.Pending).Reverse())
{
}
public bool IsCanceled { get; private set; }
public bool TryDequeue(out Tile tile)
{
tile = null;
if (IsCanceled || !TryPop(out tile))
{
return false;
}
tile.Pending = false;
return true;
}
public void Cancel()
{
IsCanceled = true;
Clear();
}
}
/// <summary>
/// Maximum number of parallel tile loading tasks. The default value is 4.
/// </summary>
@ -35,12 +65,19 @@ namespace MapControl
/// </summary>
public static TimeSpan MaxCacheExpiration { get; set; } = TimeSpan.FromDays(10);
/// <summary>
/// Reports tile loading process as double value between 0 and 1.
/// </summary>
public IProgress<double> Progress { get; set; }
/// <summary>
/// The current TileSource, passed to the most recent LoadTiles call.
/// </summary>
public TileSource TileSource { get; private set; }
private ConcurrentStack<Tile> pendingTiles;
private TileQueue pendingTiles;
private int progressTotal;
private int progressLoaded;
/// <summary>
/// Loads all pending tiles from the tiles collection.
@ -49,39 +86,47 @@ namespace MapControl
/// </summary>
public Task LoadTiles(IEnumerable<Tile> tiles, TileSource tileSource, string cacheName)
{
pendingTiles?.Clear(); // stop processing the current queue
pendingTiles?.Cancel();
TileSource = tileSource;
if (tileSource != null)
{
pendingTiles = new ConcurrentStack<Tile>(tiles.Where(tile => tile.Pending).Reverse());
pendingTiles = new TileQueue(tiles);
var numTasks = Math.Min(pendingTiles.Count, MaxLoadTasks);
if (numTasks > 0)
{
if (Progress != null)
{
progressTotal = pendingTiles.Count;
progressLoaded = 0;
Progress.Report(0d);
}
if (Cache == null || tileSource.UriFormat == null || !tileSource.UriFormat.StartsWith("http"))
{
cacheName = null; // no tile caching
}
var tasks = Enumerable.Range(0, numTasks)
.Select(_ => Task.Run(() => LoadPendingTiles(pendingTiles, tileSource, cacheName)));
return Task.WhenAll(tasks);
return Task.WhenAll(Enumerable.Range(0, numTasks).Select(
_ => Task.Run(() => LoadPendingTiles(pendingTiles, tileSource, cacheName))));
}
}
if (Progress != null && progressLoaded < progressTotal)
{
Progress.Report(1d);
}
return Task.CompletedTask;
}
private static async Task LoadPendingTiles(ConcurrentStack<Tile> pendingTiles, TileSource tileSource, string cacheName)
private async Task LoadPendingTiles(TileQueue tileQueue, TileSource tileSource, string cacheName)
{
while (pendingTiles.TryPop(out var tile))
while (tileQueue.TryDequeue(out var tile))
{
tile.Pending = false;
try
{
await LoadTile(tile, tileSource, cacheName).ConfigureAwait(false);
@ -90,6 +135,13 @@ namespace MapControl
{
Debug.WriteLine($"TileImageLoader: {tile.ZoomLevel}/{tile.XIndex}/{tile.Y}: {ex.Message}");
}
if (Progress != null && !tileQueue.IsCanceled)
{
Interlocked.Increment(ref progressLoaded);
Progress.Report((double)progressLoaded / progressTotal);
}
}
}

View file

@ -34,7 +34,14 @@ namespace MapControl
public static readonly DependencyProperty LayersProperty = DependencyProperty.Register(
nameof(Layers), typeof(string), typeof(WmsImageLayer),
new PropertyMetadata(null, async (o, e) => await ((WmsImageLayer)o).UpdateImageAsync()));
new PropertyMetadata(null,
async (o, e) =>
{
if (e.OldValue != null) // ignore initial property change from GetImageAsync
{
await ((WmsImageLayer)o).UpdateImageAsync();
}
}));
public static readonly DependencyProperty StylesProperty = DependencyProperty.Register(
nameof(Styles), typeof(string), typeof(WmsImageLayer),
@ -187,7 +194,7 @@ namespace MapControl
/// <summary>
/// Loads an ImageSource from the URL returned by GetMapRequestUri().
/// </summary>
protected override async Task<ImageSource> GetImageAsync()
protected override async Task<ImageSource> GetImageAsync(IProgress<double> progress)
{
ImageSource image = null;
@ -203,7 +210,7 @@ namespace MapControl
if (!string.IsNullOrEmpty(uri))
{
image = await ImageLoader.LoadImageAsync(new Uri(uri));
image = await ImageLoader.LoadImageAsync(new Uri(uri), progress);
}
}

View file

@ -6,8 +6,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2022 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("7.2.1")]
[assembly: AssemblyFileVersion("7.2.1")]
[assembly: AssemblyVersion("7.3.0")]
[assembly: AssemblyFileVersion("7.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -5,7 +5,7 @@
<RootNamespace>MapControl</RootNamespace>
<AssemblyTitle>XAML Map Control Library for WPF</AssemblyTitle>
<Product>XAML Map Control</Product>
<Version>7.2.1</Version>
<Version>7.3.0</Version>
<Authors>Clemens Fischer</Authors>
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
<SignAssembly>true</SignAssembly>

View file

@ -2,6 +2,7 @@
// © 2022 Clemens Fischer
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
@ -28,7 +29,7 @@ namespace MapControl
set { SetValue(ItemsSourceProperty, value); }
}
protected override async Task<ImageSource> GetImageAsync()
protected override async Task<ImageSource> GetImageAsync(IProgress<double> progress)
{
ImageSource image = null;
var projection = ParentMap?.MapProjection;

View file

@ -7,7 +7,7 @@
<RootNamespace>MapControl</RootNamespace>
<AssemblyTitle>XAML Map Control Library for WinUI</AssemblyTitle>
<Product>XAML Map Control</Product>
<Version>7.2.1</Version>
<Version>7.3.0</Version>
<Authors>Clemens Fischer</Authors>
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
<SignAssembly>true</SignAssembly>

View file

@ -6,8 +6,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2022 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("7.2.1")]
[assembly: AssemblyFileVersion("7.2.1")]
[assembly: AssemblyVersion("7.3.0")]
[assembly: AssemblyFileVersion("7.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -5,7 +5,7 @@
<RootNamespace>MapControl.Projections</RootNamespace>
<AssemblyTitle>XAML Map Control Projections Library for WPF</AssemblyTitle>
<Product>XAML Map Control</Product>
<Version>7.2.1</Version>
<Version>7.3.0</Version>
<Authors>Clemens Fischer</Authors>
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
<SignAssembly>true</SignAssembly>

View file

@ -7,7 +7,7 @@
<RootNamespace>MapControl.Projections</RootNamespace>
<AssemblyTitle>XAML Map Control Projections Library for WinUI</AssemblyTitle>
<Product>XAML Map Control</Product>
<Version>7.2.1</Version>
<Version>7.3.0</Version>
<Authors>Clemens Fischer</Authors>
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
<SignAssembly>true</SignAssembly>

View file

@ -6,8 +6,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2022 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("7.2.1")]
[assembly: AssemblyFileVersion("7.2.1")]
[assembly: AssemblyVersion("7.3.0")]
[assembly: AssemblyFileVersion("7.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -5,7 +5,7 @@
<RootNamespace>MapControl.UiTools</RootNamespace>
<AssemblyTitle>XAML Map Control UI Tools Library for WPF</AssemblyTitle>
<Product>XAML Map Control</Product>
<Version>7.2.1</Version>
<Version>7.3.0</Version>
<Authors>Clemens Fischer</Authors>
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
<SignAssembly>true</SignAssembly>

View file

@ -7,7 +7,7 @@
<RootNamespace>MapControl.UiTools</RootNamespace>
<AssemblyTitle>XAML Map Control UI Tools Library for WinUI</AssemblyTitle>
<Product>XAML Map Control</Product>
<Version>7.2.1</Version>
<Version>7.3.0</Version>
<Authors>Clemens Fischer</Authors>
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
<SignAssembly>true</SignAssembly>

View file

@ -6,8 +6,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2022 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("7.2.1")]
[assembly: AssemblyFileVersion("7.2.1")]
[assembly: AssemblyVersion("7.3.0")]
[assembly: AssemblyFileVersion("7.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -5,7 +5,7 @@
<RootNamespace>MapControl.Caching</RootNamespace>
<AssemblyTitle>XAML Map Control SQLiteCache Library for WPF</AssemblyTitle>
<Product>XAML Map Control</Product>
<Version>7.2.1</Version>
<Version>7.3.0</Version>
<Authors>Clemens Fischer</Authors>
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
<SignAssembly>true</SignAssembly>

View file

@ -7,7 +7,7 @@
<RootNamespace>MapControl.Caching</RootNamespace>
<AssemblyTitle>XAML Map Control SQLiteCache Library for WinUI</AssemblyTitle>
<Product>XAML Map Control</Product>
<Version>7.2.1</Version>
<Version>7.3.0</Version>
<Authors>Clemens Fischer</Authors>
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
<SignAssembly>true</SignAssembly>

View file

@ -6,7 +6,7 @@
<RootNamespace>ProjectionDemo</RootNamespace>
<AssemblyTitle>XAML Map Control Projection Demo Application</AssemblyTitle>
<Product>XAML Map Control</Product>
<Version>7.2.1</Version>
<Version>7.3.0</Version>
<Authors>Clemens Fischer</Authors>
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
</PropertyGroup>

View file

@ -13,11 +13,18 @@ using System.Windows.Data;
namespace SampleApplication
{
public class HeadingToVisibilityConverter : IValueConverter
public class DoubleToVisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, string language)
{
return (double)value != 0d ? Visibility.Visible : Visibility.Collapsed;
if (!(parameter is double p))
{
p = double.Parse(parameter.ToString());
}
//System.Diagnostics.Debug.WriteLine((double)value);
return (double)value != p ? Visibility.Visible : Visibility.Collapsed;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)

View file

@ -80,6 +80,8 @@
</Setter.Value>
</Setter>
</Style>
<local:DoubleToVisibilityConverter x:Key="DoubleToVisibilityConverter"/>
</Grid.Resources>
<Grid.DataContext>
@ -214,14 +216,8 @@
Maximum="{Binding MaxZoomLevel, ElementName=map}"
Value="{Binding TargetZoomLevel, ElementName=map, Mode=TwoWay}"/>
<Button Margin="2" Padding="8" ToolTipService.ToolTip="Reset Heading" Click="ResetHeadingButtonClick">
<Button.Visibility>
<Binding Path="Heading" ElementName="map">
<Binding.Converter>
<local:HeadingToVisibilityConverter/>
</Binding.Converter>
</Binding>
</Button.Visibility>
<Button Margin="2" Padding="8" ToolTipService.ToolTip="Reset Heading" Click="ResetHeadingButtonClick"
Visibility="{Binding Heading, ElementName=map, Converter={StaticResource DoubleToVisibilityConverter}, ConverterParameter=0}">
<FontIcon Glyph="&#xEBE6;"/>
</Button>
</StackPanel>

View file

@ -6,8 +6,8 @@ using System.Runtime.InteropServices;
[assembly: AssemblyCompany("Clemens Fischer")]
[assembly: AssemblyCopyright("Copyright © 2022 Clemens Fischer")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyVersion("7.2.1")]
[assembly: AssemblyFileVersion("7.2.1")]
[assembly: AssemblyVersion("7.3.0")]
[assembly: AssemblyFileVersion("7.3.0")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]

View file

@ -81,6 +81,7 @@
</Setter>
</Style>
<local:DoubleToVisibilityConverter x:Key="DoubleToVisibilityConverter"/>
</Grid.Resources>
<Grid.DataContext>
@ -112,10 +113,15 @@
</map:Pushpin>
</map:Map>
<Border HorizontalAlignment="Right" VerticalAlignment="Bottom" Background="#AFFFFFFF">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Bottom" Background="#AFFFFFFF">
<ProgressBar Width="100" Height="10" Margin="4,2" Maximum="1"
Value="{Binding MapLayer.LoadingProgress, ElementName=map}"
Visibility="{Binding Value, RelativeSource={RelativeSource Self}, Converter={StaticResource DoubleToVisibilityConverter}, ConverterParameter=1}"/>
<TextBlock Margin="4,2" FontSize="10"
local:HyperlinkText.InlinesSource="{Binding MapLayer.Description, ElementName=map}"/>
</Border>
</StackPanel>
<Border HorizontalAlignment="Center" VerticalAlignment="Top" Margin="4"
Background="#AFFFFFFF" IsHitTestVisible="False">
@ -214,14 +220,8 @@
Maximum="{Binding MaxZoomLevel, ElementName=map}"
Value="{Binding TargetZoomLevel, ElementName=map, Mode=TwoWay}"/>
<Button Margin="2" Padding="8" ToolTipService.ToolTip="Reset Heading" Click="ResetHeadingButtonClick">
<Button.Visibility>
<Binding Path="Heading" ElementName="map">
<Binding.Converter>
<local:HeadingToVisibilityConverter/>
</Binding.Converter>
</Binding>
</Button.Visibility>
<Button Margin="2" Padding="8" ToolTipService.ToolTip="Reset Heading" Click="ResetHeadingButtonClick"
Visibility="{Binding Heading, ElementName=map, Converter={StaticResource DoubleToVisibilityConverter}, ConverterParameter=0}">
<FontIcon Glyph="&#xEBE6;"/>
</Button>
</StackPanel>

View file

@ -11,7 +11,7 @@
<RootNamespace>SampleApplication</RootNamespace>
<AssemblyTitle>XAML Map Control WinUI Sample Application</AssemblyTitle>
<Product>XAML Map Control</Product>
<Version>7.2.1</Version>
<Version>7.3.0</Version>
<Authors>Clemens Fischer</Authors>
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
<AnalysisLevel>none</AnalysisLevel>

View file

@ -138,10 +138,26 @@
<map:Pushpin AutoCollapse="True" Location="53.5,8.2" Content="N 53°30' E 8°12'"/>
</map:Map>
<Border HorizontalAlignment="Right" VerticalAlignment="Bottom" Background="#AFFFFFFF">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Bottom" Background="#AFFFFFFF">
<ProgressBar Width="100" Height="8" Margin="4,2" VerticalAlignment="Center" Maximum="1"
Value="{Binding MapLayer.LoadingProgress, ElementName=map}">
<ProgressBar.Style>
<Style TargetType="ProgressBar">
<Style.Triggers>
<Trigger Property="Value" Value="0">
<Setter Property="IsIndeterminate" Value="True"/>
</Trigger>
<Trigger Property="Value" Value="1">
<Setter Property="Visibility" Value="Collapsed"/>
</Trigger>
</Style.Triggers>
</Style>
</ProgressBar.Style>
</ProgressBar>
<TextBlock Margin="4,2" FontSize="10"
local:HyperlinkText.InlinesSource="{Binding MapLayer.Description, ElementName=map}"/>
</Border>
</StackPanel>
<local:OutlinedText
x:Name="mouseLocation" Margin="4" FontFamily="Consolas"
@ -191,13 +207,15 @@
<Button Margin="2" Padding="8" ToolTip="Reset Heading" Click="ResetHeadingButtonClick"
FontSize="20" FontFamily="Segoe MDL2 Assets" Content="&#xEBE6;">
<Button.Visibility>
<Binding Path="Heading" ElementName="map">
<Binding.Converter>
<local:HeadingToVisibilityConverter/>
</Binding.Converter>
</Binding>
</Button.Visibility>
<Button.Style>
<Style TargetType="Button">
<Style.Triggers>
<DataTrigger Binding="{Binding Heading, ElementName=map}" Value="0">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
</StackPanel>
</Grid>

View file

@ -6,7 +6,7 @@
<RootNamespace>SampleApplication</RootNamespace>
<AssemblyTitle>XAML Map Control WPF Sample Application</AssemblyTitle>
<Product>XAML Map Control</Product>
<Version>7.2.1</Version>
<Version>7.3.0</Version>
<Authors>Clemens Fischer</Authors>
<Copyright>Copyright © 2022 Clemens Fischer</Copyright>
<DefineConstants></DefineConstants>