diff options
Diffstat (limited to 'Xamarin.Forms.Platform.WP8/ImageRenderer.cs')
-rw-r--r-- | Xamarin.Forms.Platform.WP8/ImageRenderer.cs | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.WP8/ImageRenderer.cs b/Xamarin.Forms.Platform.WP8/ImageRenderer.cs new file mode 100644 index 00000000..8be9c15d --- /dev/null +++ b/Xamarin.Forms.Platform.WP8/ImageRenderer.cs @@ -0,0 +1,166 @@ +using System; +using System.ComponentModel; +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace Xamarin.Forms.Platform.WinPhone +{ + internal static class ImageExtensions + { + public static Stretch ToStretch(this Aspect aspect) + { + switch (aspect) + { + case Aspect.Fill: + return Stretch.Fill; + case Aspect.AspectFill: + return Stretch.UniformToFill; + default: + case Aspect.AspectFit: + return Stretch.Uniform; + } + } + } + + public class ImageRenderer : ViewRenderer<Image, System.Windows.Controls.Image> + { + public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint) + { + // Someone reported a NRE happening in this method which can only be explained by Control being null + // which only happens at the very beginning of the view lifecycle. Honest I have no idea how this might + // happen because it really shouldn't measure at that point. Add check anyway and live in fear... + if (Control?.Source == null) + return new SizeRequest(); + + var result = new Size { Width = ((BitmapImage)Control.Source).PixelWidth, Height = ((BitmapImage)Control.Source).PixelHeight }; + + return new SizeRequest(result); + } + + protected override void OnElementChanged(ElementChangedEventArgs<Image> e) + { + base.OnElementChanged(e); + + if (e.NewElement != null) + { + if (Control == null) + { + var image = new System.Windows.Controls.Image(); + SetNativeControl(image); + } + + SetSource(Control); + SetAspect(Control); + } + } + + protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) + { + base.OnElementPropertyChanged(sender, e); + + if (e.PropertyName == Image.SourceProperty.PropertyName) + SetSource(Control); + else if (e.PropertyName == Image.AspectProperty.PropertyName) + SetAspect(Control); + } + + void SetAspect(System.Windows.Controls.Image image) + { + Aspect aspect = Element.Aspect; + + image.Stretch = aspect.ToStretch(); + } + + async void SetSource(System.Windows.Controls.Image image) + { + ((IElementController)Element).SetValueFromRenderer(Image.IsLoadingPropertyKey, true); + + ImageSource source = Element.Source; + IImageSourceHandler handler; + if (source != null && (handler = Registrar.Registered.GetHandler<IImageSourceHandler>(source.GetType())) != null) + { + System.Windows.Media.ImageSource imagesource; + try + { + imagesource = await handler.LoadImageAsync(source); + } + catch (TaskCanceledException) + { + imagesource = null; + } + image.Source = imagesource; + // if you dont at least measure the thing once it wont load the image + // then the whole thing falls over. + image.Measure(new System.Windows.Size(100, 100)); + ((IVisualElementController)Element).NativeSizeChanged(); + } + else + image.Source = null; + + ((IElementController)Element).SetValueFromRenderer(Image.IsLoadingPropertyKey, false); + } + } + + public interface IImageSourceHandler : IRegisterable + { + Task<System.Windows.Media.ImageSource> LoadImageAsync(ImageSource imagesoure, CancellationToken cancelationToken = default(CancellationToken)); + } + + public sealed class FileImageSourceHandler : IImageSourceHandler + { + public Task<System.Windows.Media.ImageSource> LoadImageAsync(ImageSource imagesoure, CancellationToken cancelationToken = new CancellationToken()) + { + System.Windows.Media.ImageSource image = null; + var filesource = imagesoure as FileImageSource; + if (filesource != null) + { + string file = filesource.File; + image = new BitmapImage(new Uri("/" + file, UriKind.Relative)); + } + return Task.FromResult(image); + } + } + + public sealed class StreamImagesourceHandler : IImageSourceHandler + { + public async Task<System.Windows.Media.ImageSource> LoadImageAsync(ImageSource imagesource, CancellationToken cancelationToken = new CancellationToken()) + { + BitmapImage bitmapimage = null; + + var streamsource = imagesource as StreamImageSource; + if (streamsource != null && streamsource.Stream != null) + { + using(Stream stream = await streamsource.GetStreamAsync(cancelationToken)) + { + bitmapimage = new BitmapImage(); + bitmapimage.SetSource(stream); + } + } + return (System.Windows.Media.ImageSource)bitmapimage; + } + } + + public sealed class ImageLoaderSourceHandler : IImageSourceHandler + { + public async Task<System.Windows.Media.ImageSource> LoadImageAsync(ImageSource imagesoure, CancellationToken cancelationToken = new CancellationToken()) + { + BitmapImage bitmapimage = null; + var imageLoader = imagesoure as UriImageSource; + if (imageLoader != null && imageLoader.Uri != null) + { + using(Stream streamimage = await imageLoader.GetStreamAsync(cancelationToken)) + { + if (streamimage != null && streamimage.CanRead) + { + bitmapimage = new BitmapImage(); + bitmapimage.SetSource(streamimage); + } + } + } + return bitmapimage; + } + } +}
\ No newline at end of file |