private void ResetImage() { if (!HasImage) { return; } _surface.Background = null; if (_brush != null) { _brush.ImageSource = null; _brush = null; } if (_source != null) { _source.ClearResources(); _source = null; } HasImage = false; }
private async void ShowImage() { if (!CanLoad || !HasAppliedTemplate || !IsLoaded || HasImage) { return; } ResetImage(); if (UriSource == null) { return; } SetProgress(0); VisualStateManager.GoToState(this, "Unloaded", true); // For thread safety, save current value of UriSource var uriSource = UriSource; HasImage = true; using (var stream = await GetImageStreamAsync(uriSource)) // This is not thread-safe! { // Technically, at each await exists the possibility that UriSource can be changed. // We need to ensure that this hasn't happened, otherwise we run the risk of leaking resources // or doing other bad things. if (uriSource != UriSource) { return; } if (stream == null) { VisualStateManager.GoToState(this, "Failed", true); return; } try { var decoder = await BitmapDecoder.CreateAsync(stream); var source = new GifImageSource((int)decoder.PixelWidth, (int)decoder.PixelHeight) { EnablePrerender = true }; await source.SetSourceAsync(stream); // It's possible that the URI changed, or the control has been unloaded, etc. If so, // clear resources and quit. if (uriSource != UriSource || !IsLoaded || !CanLoad) { // Clean up GifImageSource and return source.ClearResources(); return; } // Must wait for async operations to complete before setting _source _source = source; } catch (Exception) { VisualStateManager.GoToState(this, "Failed", true); return; } } _brush = new ImageBrush { ImageSource = _source, Stretch = Stretch.None }; _surface.Background = _brush; _surface.Height = _source.Height; _surface.Width = _source.Width; // Render one frame so that we show something even if the gif is paused _source.RenderFrame(); VisualStateManager.GoToState(this, "Loaded", true); CheckTimer(); _fireImageOpened = true; }