public static async Task ApplyDrawableAsync(this IVisualElementRenderer renderer, BindableObject bindable, BindableProperty imageSourceProperty, Context context, Action <Drawable> onSet, Action <bool> onLoading = null, CancellationToken cancellationToken = default(CancellationToken)) { _ = context ?? throw new ArgumentNullException(nameof(context)); _ = imageSourceProperty ?? throw new ArgumentNullException(nameof(imageSourceProperty)); _ = onSet ?? throw new ArgumentNullException(nameof(onSet)); // make sure things are good before we start BindableObject element = null; if (!renderer.IsDrawableSourceValid(bindable, out element)) { return; } onLoading?.Invoke(true); if (element.GetValue(imageSourceProperty) is ImageSource initialSource && !initialSource.IsEmpty) { try { string cacheKey = String.Empty; // Todo improve for other sources // volley the requests better up front so that if the same request comes in it isn't requeued if (initialSource is UriImageSource uri && uri.CachingEnabled) { cacheKey = Device.PlatformServices.GetMD5Hash(uri.Uri.ToString()); var cacheObject = await GetCache().GetAsync(cacheKey, uri.CacheValidity, async() => { var drawable = await context.GetFormsDrawableAsync(initialSource, cancellationToken); return(drawable); }); Drawable returnValue = null; if (cacheObject is Bitmap bitmap) { returnValue = new BitmapDrawable(context.Resources, bitmap); } else { returnValue = cacheObject as Drawable; } if (!renderer.IsDrawableSourceValid(bindable, out element)) { return; } // only set if we are still on the same image if (element.GetValue(imageSourceProperty) == initialSource) { using (returnValue) onSet(returnValue); } } else { using (var drawable = await context.GetFormsDrawableAsync(initialSource, cancellationToken)) { if (!renderer.IsDrawableSourceValid(bindable, out element)) { return; } // only set if we are still on the same image if (element.GetValue(imageSourceProperty) == initialSource) { onSet(drawable); } } } }