The Windows Community Toolkit includes an ImageEx control that can be used to manage both local caching of remote images and asynhcronous loading of the images in the UI.
As a side effect of how they have implemented the downloading of the image we can access the static HttpClient
instance that it uses and set the DefaultRequestHeaders
with Authentication or other Headers that your API may require.
This solution works if all your images are hosted from the same authenticated server, the toolkit is open source so you can download the source code and change the implementation for your own needs.
The ImageEx control manages the Visible state while the image is being loaded with a nice fade in animation by default, however you can override this or even provide a PlaceHolder
image or text.
- An advanced scenario is to use the
PlaceHolder
to first render a low-res version of the image that may be aggressively cached. That's out-of-scope for this post, but highlights the extensibility of this solution.
The magic happens inside the ImageCache that this control uses, we can force the ImageCache to be used by setting both EnableLazyLoading
and the IsCacheEnabled
properties to True
, as long as we set the request headers before the images are loaded then we can bind the Source
directly to the external URL to access the files.
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
<controls.ImageEx Width="50"
Height="50"
Stretch="UniformToFill"
HorizontalAlignment="Center"
VerticalAlignment="Center"
EnableLazyLoading="True"
IsCacheEnabled="True"
Source="{Binding ImageUrl}" />
This behaviour is not explicitly documented, by using reflection to access the internal HttpClient
we accept there is a risk that this may not work in future versions.
Ideally, becuase ImageCache.Instance is a static member, we only need to set the Auth headers when the user logs in, the following code shows how you can do this with an arbitrary header:
// set the auth header on the Image Cache!
var httpClient = ImageCache.Instance
.GetType()
.GetProperty("HttpClient", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.NonPublic)
.GetValue(ImageCache.Instance)
as System.Net.Http.HttpClient;
Runtime.ConfigureHttpClient(httpClient);
httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "---MyUserAuthToken---");
httpClient.DefaultRequestHeaders.Add("My-Token", "---arbitrary token---");
The runtime performance is great, but you can configure the ImageCache
to keep a number of the images in memory, or we can explicitly or pre-emptively load images in advance:
In the following, assume that item
is a data object that has an ImageUrl
that holds a URL to a resource that requires authentication.
// Define max memory cache size
ImageCache.Instance.MaxMemoryCacheCount = 200;
// Precache data and save it in memory
await ImageCache.Instance.PreCacheAsync(new Uri(item.ImageUrl), Path.GetFileName(item.Thumbnail), true);
// Precache data and save it in on local hard drive
await ImageCache.Instance.PreCacheAsync(new Uri(item.ImageUrl), Path.GetFileName(item.Thumbnail), false);
// Clear cache
await ImageCache.Instance.ClearAsync();