Skip to content
23 changes: 23 additions & 0 deletions Microsoft.Toolkit.Uwp.UI.Controls/ImageEx/CachingStrategy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// The type of caching to be applied to <see cref="ImageEx"/>.
/// Default is <see cref="Custom"/>
/// </summary>
public enum ImageExCachingStrategy
{
/// <summary>
/// Caching is handled by <see cref="ImageEx"/>'s custom caching system.
/// </summary>
Custom,

/// <summary>
/// Caching is handled internally by UWP.
/// </summary>
Internal
}
}
14 changes: 14 additions & 0 deletions Microsoft.Toolkit.Uwp.UI.Controls/ImageEx/ImageExBase.Members.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ public partial class ImageExBase
/// </summary>
public static readonly DependencyProperty IsCacheEnabledProperty = DependencyProperty.Register(nameof(IsCacheEnabled), typeof(bool), typeof(ImageExBase), new PropertyMetadata(false));

/// <summary>
/// Identifies the <see cref="CachingStrategy"/> dependency property.
/// </summary>
public static readonly DependencyProperty CachingStrategyProperty = DependencyProperty.Register(nameof(CachingStrategy), typeof(ImageExCachingStrategy), typeof(ImageExBase), new PropertyMetadata(ImageExCachingStrategy.Custom));

/// <summary>
/// Returns a mask that represents the alpha channel of an image as a <see cref="CompositionBrush"/>
/// </summary>
Expand Down Expand Up @@ -125,5 +130,14 @@ public bool IsCacheEnabled
get { return (bool)GetValue(IsCacheEnabledProperty); }
set { SetValue(IsCacheEnabledProperty, value); }
}

/// <summary>
/// Gets or sets a value indicating how the <see cref="ImageEx"/> will be cached.
/// </summary>
public ImageExCachingStrategy CachingStrategy
{
get { return (ImageExCachingStrategy)GetValue(CachingStrategyProperty); }
set { SetValue(CachingStrategyProperty, value); }
}
}
}
110 changes: 64 additions & 46 deletions Microsoft.Toolkit.Uwp.UI.Controls/ImageEx/ImageExBase.Source.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,60 +121,78 @@ private async Task LoadImageAsync(Uri imageUri)
{
if (_uri != null)
{
if (IsCacheEnabled && _isHttpSource)
if (IsCacheEnabled)
{
try
switch (CachingStrategy)
{
var propValues = new List<KeyValuePair<string, object>>();

if (DecodePixelHeight > 0)
{
propValues.Add(new KeyValuePair<string, object>(nameof(DecodePixelHeight), DecodePixelHeight));
}

if (DecodePixelWidth > 0)
{
propValues.Add(new KeyValuePair<string, object>(nameof(DecodePixelWidth), DecodePixelWidth));
}

if (propValues.Count > 0)
{
propValues.Add(new KeyValuePair<string, object>(nameof(DecodePixelType), DecodePixelType));
}

var img = await ImageCache.Instance.GetFromCacheAsync(imageUri, true, _tokenSource.Token, propValues);

lock (LockObj)
{
// If you have many imageEx in a virtualized listview for instance
// controls will be recycled and the uri will change while waiting for the previous one to load
if (_uri == imageUri)
{
AttachSource(img);
ImageExOpened?.Invoke(this, new ImageExOpenedEventArgs());
VisualStateManager.GoToState(this, LoadedState, true);
}
}
case ImageExCachingStrategy.Custom when _isHttpSource:
await SetHttpSourceCustomCached(imageUri);
break;
case ImageExCachingStrategy.Custom:
case ImageExCachingStrategy.Internal:
default:
AttachSource(new BitmapImage(imageUri));
break;
}
catch (OperationCanceledException)
}
else
{
AttachSource(new BitmapImage(_uri)
{
// nothing to do as cancellation has been requested.
}
catch (Exception e)
CreateOptions = BitmapCreateOptions.IgnoreImageCache
});
}
}
}

private async Task SetHttpSourceCustomCached(Uri imageUri)
{
try
{
var propValues = new List<KeyValuePair<string, object>>();

if (DecodePixelHeight > 0)
{
propValues.Add(new KeyValuePair<string, object>(nameof(DecodePixelHeight), DecodePixelHeight));
}

if (DecodePixelWidth > 0)
{
propValues.Add(new KeyValuePair<string, object>(nameof(DecodePixelWidth), DecodePixelWidth));
}

if (propValues.Count > 0)
{
propValues.Add(new KeyValuePair<string, object>(nameof(DecodePixelType), DecodePixelType));
}

var img = await ImageCache.Instance.GetFromCacheAsync(imageUri, true, _tokenSource.Token, propValues);

lock (LockObj)
{
// If you have many imageEx in a virtualized listview for instance
// controls will be recycled and the uri will change while waiting for the previous one to load
if (_uri == imageUri)
{
lock (LockObj)
{
if (_uri == imageUri)
{
ImageExFailed?.Invoke(this, new ImageExFailedEventArgs(e));
VisualStateManager.GoToState(this, FailedState, true);
}
}
AttachSource(img);
ImageExOpened?.Invoke(this, new ImageExOpenedEventArgs());
VisualStateManager.GoToState(this, LoadedState, true);
}
}
else
}
catch (OperationCanceledException)
{
// nothing to do as cancellation has been requested.
}
catch (Exception e)
{
lock (LockObj)
{
AttachSource(new BitmapImage(_uri));
if (_uri == imageUri)
{
ImageExFailed?.Invoke(this, new ImageExFailedEventArgs(e));
VisualStateManager.GoToState(this, FailedState, true);
}
}
}
}
Expand Down
4 changes: 3 additions & 1 deletion docs/controls/ImageEx.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ keywords: windows 10, uwp, windows community toolkit, uwp community toolkit, uwp
# ImageEx XAML Control

The [ImageEx Control](https://docs.microsoft.com/dotnet/api/microsoft.toolkit.uwp.ui.controls.imageex) and [RoundImageEx Control](https://docs.microsoft.com/dotnet/api/microsoft.toolkit.uwp.ui.controls.roundimageex) downloads images asynchronously, while showing a loading indicator. Source images are then stored in the application's local cache to preserve resources and load time. ImageEx also extends the default *Image* and *ImageBrush* Platform controls respectively to improve performance through caching. You can also use a placeholder image that will be displayed while loading the main image.

## Syntax

```xaml
Expand All @@ -33,6 +33,8 @@ On Windows 10.0.16299.0 or higher, `CornerRadius` is supported on ImageEx. Use
| Property | Type | Description |
| -- | -- | -- |
| NineGrid | Thickness | Gets or sets the nine-grid used by the image |
| IsCacheEnabled | bool | Gets or sets a value indicating whether gets or sets cache state |
| ImageExCachingStrategy | enum | Gets or sets a value indicating how the Image will be cached |

## RoundImageEx Properties

Expand Down