Skip to content

Instantly share code, notes, and snippets.

@clairernovotny
Last active August 29, 2015 14:13
Show Gist options
  • Save clairernovotny/37b28ce8e7eee4ce61d2 to your computer and use it in GitHub Desktop.
Save clairernovotny/37b28ce8e7eee4ce61d2 to your computer and use it in GitHub Desktop.
Image Renderer for WP8 Images
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using News.Controls;
using News.WinPhone.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.WinPhone;
using Size = Xamarin.Forms.Size;
[assembly: ExportRenderer(typeof(WImage), typeof(WImageRenderer))]
namespace News.WinPhone.Renderers
{
class WImageRenderer : ViewRenderer<Xamarin.Forms.Image, System.Windows.Controls.Image>
{
protected override void OnElementChanged(ElementChangedEventArgs<Image> e)
{
base.OnElementChanged(e);
var image = new System.Windows.Controls.Image();
image.Unloaded += ImageOnUnloaded;
SetAspect(image);
SetSource(image);
SetNativeControl(image);
}
private void ImageOnUnloaded(object sender, RoutedEventArgs routedEventArgs)
{
Control.Unloaded -= ImageOnUnloaded;
var img = Control.Source as BitmapImage;
if (img != null)
DisposeImage(img);
}
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Image.SourceProperty.PropertyName)
{
SetSource(Control);
}
else
{
if (!(e.PropertyName == Xamarin.Forms.Image.AspectProperty.PropertyName))
return;
SetAspect(Control);
}
}
private void SetSource(System.Windows.Controls.Image image)
{
var src = Element.Source as UriImageSource;
IVisualElementController controller = Element;
// see if there's ane existing bitmap source
var oldSource = image.Source as BitmapImage;
if (src != null && src.Uri != null)
{
var img = new BitmapImage(src.Uri)
{
CreateOptions = BitmapCreateOptions.BackgroundCreation
};
if (Element.HeightRequest > 0)
{
img.DecodePixelHeight = (int)Element.HeightRequest;
}
if (Element.WidthRequest > 0)
{
img.DecodePixelWidth = (int)Element.WidthRequest;
}
image.Source = img;
controller.NativeSizeChanged();
}
else
{
image.Source = null;
}
if (oldSource != null)
{
DisposeImage(oldSource);
}
}
private void SetAspect(System.Windows.Controls.Image image)
{
var aspect = this.Element.Aspect;
image.Stretch = ToStretch(aspect);
}
public override SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint)
{
if (Control.Source == null)
return new SizeRequest();
return new SizeRequest(new Size()
{
Width = ((BitmapSource)Control.Source).PixelWidth,
Height = ((BitmapSource)Control.Source).PixelHeight
});
}
private static Stretch ToStretch(Aspect aspect)
{
switch (aspect)
{
case Aspect.AspectFill:
return Stretch.UniformToFill;
case Aspect.Fill:
return Stretch.Fill;
default:
return Stretch.Uniform;
}
}
/// <summary>
/// Force a <see cref="BitmapImage"/> to free up the image resources.
/// This is a "hack" used because setting a null Source URI does not feee-up
/// the bitmap raw data memory.
///
/// http://stackoverflow.com/questions/13816569/windows-phone-listbox-with-images-out-of-memory
/// </summary>
/// <param name="image"></param>
private static void DisposeImage(BitmapImage image)
{
var uri = new Uri("News.WinPhone;component/Assets/11.png", UriKind.RelativeOrAbsolute);
var sr = System.Windows.Application.GetResourceStream(uri);
try
{
using (var stream = sr.Stream)
{
image.DecodePixelWidth = 1; // This is essential!
image.DecodePixelHeight = 1; // This is essential!
image.SetSource(stream);
}
}
catch
{ }
}
}
}
@clairernovotny
Copy link
Author

Grab the 1x1 png from here (http://i.imgur.com/DwJIfJt.png) and rename it to 11.png, then put it in your /Assets folder with a build action of Resource.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment