mirror of
https://github.com/ClemensFischer/XAML-Map-Control.git
synced 2025-12-06 07:12:04 +01:00
Moved asynchronous image loading to Tile class
This commit is contained in:
parent
2f9c50fb47
commit
f4d43eeb44
|
|
@ -1,33 +1,47 @@
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Animation;
|
using Avalonia.Animation;
|
||||||
|
using Avalonia.Media;
|
||||||
using Avalonia.Styling;
|
using Avalonia.Styling;
|
||||||
|
using Avalonia.Threading;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
public partial class Tile
|
public partial class Tile
|
||||||
{
|
{
|
||||||
private void FadeIn()
|
public async Task LoadImageAsync(Func<Task<IImage>> loadImageFunc)
|
||||||
{
|
{
|
||||||
var fadeInAnimation = new Animation
|
var image = await loadImageFunc().ConfigureAwait(false);
|
||||||
{
|
|
||||||
Duration = MapBase.ImageFadeDuration,
|
|
||||||
Children =
|
|
||||||
{
|
|
||||||
new KeyFrame
|
|
||||||
{
|
|
||||||
KeyTime = TimeSpan.Zero,
|
|
||||||
Setters = { new Setter(Visual.OpacityProperty, 0d) }
|
|
||||||
},
|
|
||||||
new KeyFrame
|
|
||||||
{
|
|
||||||
KeyTime = MapBase.ImageFadeDuration,
|
|
||||||
Setters = { new Setter(Visual.OpacityProperty, 1d) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
_ = fadeInAnimation.RunAsync(Image);
|
await Dispatcher.UIThread.InvokeAsync(
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
Image.Source = image;
|
||||||
|
|
||||||
|
if (image != null && MapBase.ImageFadeDuration > TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
var fadeInAnimation = new Animation
|
||||||
|
{
|
||||||
|
Duration = MapBase.ImageFadeDuration,
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
new KeyFrame
|
||||||
|
{
|
||||||
|
KeyTime = TimeSpan.Zero,
|
||||||
|
Setters = { new Setter(Visual.OpacityProperty, 0d) }
|
||||||
|
},
|
||||||
|
new KeyFrame
|
||||||
|
{
|
||||||
|
KeyTime = MapBase.ImageFadeDuration,
|
||||||
|
Setters = { new Setter(Visual.OpacityProperty, 1d) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
_ = fadeInAnimation.RunAsync(Image);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,18 +0,0 @@
|
||||||
using Avalonia.Media;
|
|
||||||
using Avalonia.Threading;
|
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
public partial class TileImageLoader
|
|
||||||
{
|
|
||||||
private static async Task LoadTileImage(Tile tile, Func<Task<IImage>> loadImageFunc)
|
|
||||||
{
|
|
||||||
var image = await loadImageFunc().ConfigureAwait(false);
|
|
||||||
|
|
||||||
await Dispatcher.UIThread.InvokeAsync(() => tile.SetImageSource(image));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
using System;
|
#if WPF
|
||||||
#if WPF
|
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
#elif UWP
|
#elif UWP
|
||||||
|
|
@ -25,25 +24,12 @@ namespace MapControl
|
||||||
Column = ((x % columnCount) + columnCount) % columnCount;
|
Column = ((x % columnCount) + columnCount) % columnCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Image Image { get; } = new Image { Stretch = Stretch.Fill };
|
||||||
public int ZoomLevel { get; }
|
public int ZoomLevel { get; }
|
||||||
public int X { get; }
|
public int X { get; }
|
||||||
public int Y { get; }
|
public int Y { get; }
|
||||||
public int Column { get; }
|
public int Column { get; }
|
||||||
public int Row => Y;
|
public int Row => Y;
|
||||||
|
|
||||||
public Image Image { get; } = new Image { Stretch = Stretch.Fill };
|
|
||||||
|
|
||||||
public bool IsPending { get; set; } = true;
|
public bool IsPending { get; set; } = true;
|
||||||
|
|
||||||
public void SetImageSource(ImageSource image)
|
|
||||||
{
|
|
||||||
IsPending = false;
|
|
||||||
Image.Source = image;
|
|
||||||
|
|
||||||
if (image != null && MapBase.ImageFadeDuration > TimeSpan.Zero)
|
|
||||||
{
|
|
||||||
FadeIn();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,13 +7,6 @@ using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
#if WPF
|
|
||||||
using System.Windows.Media;
|
|
||||||
#elif UWP
|
|
||||||
using Windows.UI.Xaml.Media;
|
|
||||||
#elif WINUI
|
|
||||||
using Microsoft.UI.Xaml.Media;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace MapControl
|
namespace MapControl
|
||||||
{
|
{
|
||||||
|
|
@ -27,7 +20,7 @@ namespace MapControl
|
||||||
void CancelLoadTiles();
|
void CancelLoadTiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
public partial class TileImageLoader : ITileImageLoader
|
public class TileImageLoader : ITileImageLoader
|
||||||
{
|
{
|
||||||
private static ILogger logger;
|
private static ILogger logger;
|
||||||
private static ILogger Logger => logger ?? (logger = ImageLoader.LoggerFactory?.CreateLogger<TileImageLoader>());
|
private static ILogger Logger => logger ?? (logger = ImageLoader.LoggerFactory?.CreateLogger<TileImageLoader>());
|
||||||
|
|
@ -161,9 +154,7 @@ namespace MapControl
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(cacheName))
|
if (string.IsNullOrEmpty(cacheName))
|
||||||
{
|
{
|
||||||
Task<ImageSource> LoadImage() => tileSource.LoadImageAsync(tile.Column, tile.Row, tile.ZoomLevel);
|
await tile.LoadImageAsync(() => tileSource.LoadImageAsync(tile.Column, tile.Row, tile.ZoomLevel)).ConfigureAwait(false);
|
||||||
|
|
||||||
await LoadTileImage(tile, LoadImage).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -175,9 +166,7 @@ namespace MapControl
|
||||||
|
|
||||||
if (buffer?.Length > 0)
|
if (buffer?.Length > 0)
|
||||||
{
|
{
|
||||||
Task<ImageSource> LoadImage() => tileSource.LoadImageAsync(buffer);
|
await tile.LoadImageAsync(() => tileSource.LoadImageAsync(buffer)).ConfigureAwait(false);
|
||||||
|
|
||||||
await LoadTileImage(tile, LoadImage).ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -282,7 +282,6 @@
|
||||||
<Link>Tile.WinUI.cs</Link>
|
<Link>Tile.WinUI.cs</Link>
|
||||||
</Compile>
|
</Compile>
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="TileImageLoader.UWP.cs" />
|
|
||||||
<EmbeddedResource Include="Properties\MapControl.UWP.rd.xml" />
|
<EmbeddedResource Include="Properties\MapControl.UWP.rd.xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Windows.UI.Core;
|
|
||||||
using Windows.UI.Xaml.Media;
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
public partial class TileImageLoader
|
|
||||||
{
|
|
||||||
private static async Task LoadTileImage(Tile tile, Func<Task<ImageSource>> loadImageFunc)
|
|
||||||
{
|
|
||||||
var tcs = new TaskCompletionSource<object>();
|
|
||||||
|
|
||||||
async void LoadTileImage()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
tile.SetImageSource(await loadImageFunc());
|
|
||||||
tcs.TrySetResult(null);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
tcs.TrySetException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!await tile.Image.Dispatcher.TryRunAsync(CoreDispatcherPriority.Low, LoadTileImage))
|
|
||||||
{
|
|
||||||
tcs.TrySetCanceled();
|
|
||||||
}
|
|
||||||
|
|
||||||
await tcs.Task;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
|
|
@ -9,6 +10,30 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
public partial class Tile
|
public partial class Tile
|
||||||
{
|
{
|
||||||
|
public async Task LoadImageAsync(Func<Task<ImageSource>> loadImageFunc)
|
||||||
|
{
|
||||||
|
var image = await loadImageFunc().ConfigureAwait(false);
|
||||||
|
|
||||||
|
await Image.Dispatcher.InvokeAsync(
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
Image.Source = image;
|
||||||
|
|
||||||
|
if (image != null && MapBase.ImageFadeDuration > TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
if (image is BitmapSource bitmap && !bitmap.IsFrozen && bitmap.IsDownloading)
|
||||||
|
{
|
||||||
|
bitmap.DownloadCompleted += BitmapDownloadCompleted;
|
||||||
|
bitmap.DownloadFailed += BitmapDownloadFailed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BeginFadeInAnimation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void BeginFadeInAnimation()
|
private void BeginFadeInAnimation()
|
||||||
{
|
{
|
||||||
var fadeInAnimation = new DoubleAnimation
|
var fadeInAnimation = new DoubleAnimation
|
||||||
|
|
@ -21,19 +46,6 @@ namespace MapControl
|
||||||
Image.BeginAnimation(UIElement.OpacityProperty, fadeInAnimation);
|
Image.BeginAnimation(UIElement.OpacityProperty, fadeInAnimation);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FadeIn()
|
|
||||||
{
|
|
||||||
if (Image.Source is BitmapSource bitmap && !bitmap.IsFrozen && bitmap.IsDownloading)
|
|
||||||
{
|
|
||||||
bitmap.DownloadCompleted += BitmapDownloadCompleted;
|
|
||||||
bitmap.DownloadFailed += BitmapDownloadFailed;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BeginFadeInAnimation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BitmapDownloadCompleted(object sender, EventArgs e)
|
private void BitmapDownloadCompleted(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
var bitmap = (BitmapSource)sender;
|
var bitmap = (BitmapSource)sender;
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
public partial class TileImageLoader
|
|
||||||
{
|
|
||||||
private static async Task LoadTileImage(Tile tile, Func<Task<ImageSource>> loadImageFunc)
|
|
||||||
{
|
|
||||||
var image = await loadImageFunc().ConfigureAwait(false);
|
|
||||||
|
|
||||||
await tile.Image.Dispatcher.InvokeAsync(() => tile.SetImageSource(image));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,9 +1,15 @@
|
||||||
#if UWP
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
#if UWP
|
||||||
|
using Windows.UI.Core;
|
||||||
using Windows.UI.Xaml;
|
using Windows.UI.Xaml;
|
||||||
|
using Windows.UI.Xaml.Media;
|
||||||
using Windows.UI.Xaml.Media.Animation;
|
using Windows.UI.Xaml.Media.Animation;
|
||||||
using Windows.UI.Xaml.Media.Imaging;
|
using Windows.UI.Xaml.Media.Imaging;
|
||||||
#else
|
#else
|
||||||
|
using Microsoft.UI.Dispatching;
|
||||||
using Microsoft.UI.Xaml;
|
using Microsoft.UI.Xaml;
|
||||||
|
using Microsoft.UI.Xaml.Media;
|
||||||
using Microsoft.UI.Xaml.Media.Animation;
|
using Microsoft.UI.Xaml.Media.Animation;
|
||||||
using Microsoft.UI.Xaml.Media.Imaging;
|
using Microsoft.UI.Xaml.Media.Imaging;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -12,6 +18,50 @@ namespace MapControl
|
||||||
{
|
{
|
||||||
public partial class Tile
|
public partial class Tile
|
||||||
{
|
{
|
||||||
|
public async Task LoadImageAsync(Func<Task<ImageSource>> loadImageFunc)
|
||||||
|
{
|
||||||
|
var tcs = new TaskCompletionSource<object>();
|
||||||
|
|
||||||
|
async void LoadImage()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var image = await loadImageFunc();
|
||||||
|
|
||||||
|
Image.Source = image;
|
||||||
|
|
||||||
|
if (image != null && MapBase.ImageFadeDuration > TimeSpan.Zero)
|
||||||
|
{
|
||||||
|
if (image is BitmapImage bitmap && bitmap.UriSource != null)
|
||||||
|
{
|
||||||
|
bitmap.ImageOpened += BitmapImageOpened;
|
||||||
|
bitmap.ImageFailed += BitmapImageFailed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BeginFadeInAnimation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tcs.TrySetResult(null);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
tcs.TrySetException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#if UWP
|
||||||
|
if (!await Image.Dispatcher.TryRunAsync(CoreDispatcherPriority.Low, LoadImage))
|
||||||
|
#else
|
||||||
|
if (!Image.DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, LoadImage))
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
tcs.TrySetCanceled();
|
||||||
|
}
|
||||||
|
|
||||||
|
await tcs.Task;
|
||||||
|
}
|
||||||
|
|
||||||
private void BeginFadeInAnimation()
|
private void BeginFadeInAnimation()
|
||||||
{
|
{
|
||||||
var fadeInAnimation = new DoubleAnimation
|
var fadeInAnimation = new DoubleAnimation
|
||||||
|
|
@ -29,19 +79,6 @@ namespace MapControl
|
||||||
storyboard.Begin();
|
storyboard.Begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void FadeIn()
|
|
||||||
{
|
|
||||||
if (Image.Source is BitmapImage bitmap && bitmap.UriSource != null)
|
|
||||||
{
|
|
||||||
bitmap.ImageOpened += BitmapImageOpened;
|
|
||||||
bitmap.ImageFailed += BitmapImageFailed;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BeginFadeInAnimation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void BitmapImageOpened(object sender, RoutedEventArgs e)
|
private void BitmapImageOpened(object sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var bitmap = (BitmapImage)sender;
|
var bitmap = (BitmapImage)sender;
|
||||||
|
|
|
||||||
|
|
@ -1,36 +0,0 @@
|
||||||
using Microsoft.UI.Dispatching;
|
|
||||||
using Microsoft.UI.Xaml.Media;
|
|
||||||
using System;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace MapControl
|
|
||||||
{
|
|
||||||
public partial class TileImageLoader
|
|
||||||
{
|
|
||||||
private static Task LoadTileImage(Tile tile, Func<Task<ImageSource>> loadImageFunc)
|
|
||||||
{
|
|
||||||
var tcs = new TaskCompletionSource();
|
|
||||||
|
|
||||||
async void LoadTileImage()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
tile.SetImageSource(await loadImageFunc());
|
|
||||||
tcs.TrySetResult();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
tcs.TrySetException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!tile.Image.DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, LoadTileImage))
|
|
||||||
{
|
|
||||||
tcs.TrySetCanceled();
|
|
||||||
}
|
|
||||||
|
|
||||||
return tcs.Task;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue