Skip to content

Instantly share code, notes, and snippets.

@robfe
Created June 27, 2012 21:05
Show Gist options
  • Save robfe/3006848 to your computer and use it in GitHub Desktop.
Save robfe/3006848 to your computer and use it in GitHub Desktop.
Tilebrush equivalent for WinRT XAML apps.
public class TileCanvas : Canvas
{
public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register("ImageSource", typeof(ImageSource), typeof(TileCanvas), new PropertyMetadata(null, ImageSourceChanged));
private Size lastActualSize;
public TileCanvas()
{
LayoutUpdated += OnLayoutUpdated;
}
public ImageSource ImageSource
{
get { return (ImageSource)GetValue(ImageSourceProperty); }
set { SetValue(ImageSourceProperty, value); }
}
private void OnLayoutUpdated(object sender, object o)
{
var newSize = new Size(ActualWidth, ActualHeight);
if (lastActualSize != newSize)
{
lastActualSize = newSize;
Rebuild();
}
}
private static void ImageSourceChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
{
TileCanvas self = (TileCanvas)o;
var src = self.ImageSource;
if (src != null)
{
var image = new Image { Source = src };
image.ImageOpened += self.ImageOnImageOpened;
image.ImageFailed += self.ImageOnImageFailed;
//add it to the visual tree to kick off ImageOpened
self.Children.Add(image);
}
}
private void ImageOnImageFailed(object sender, ExceptionRoutedEventArgs exceptionRoutedEventArgs)
{
var image = (Image)sender;
image.ImageOpened -= ImageOnImageOpened;
image.ImageFailed -= ImageOnImageFailed;
Children.Add(new TextBlock { Text = exceptionRoutedEventArgs.ErrorMessage, Foreground = new SolidColorBrush(Colors.Red) });
}
private void ImageOnImageOpened(object sender, RoutedEventArgs routedEventArgs)
{
var image = (Image) sender;
image.ImageOpened -= ImageOnImageOpened;
image.ImageFailed -= ImageOnImageFailed;
Rebuild();
}
private void Rebuild()
{
var bmp = ImageSource as BitmapSource;
if (bmp == null)
{
return;
}
var width = bmp.PixelWidth;
var height = bmp.PixelHeight;
if(width == 0 || height == 0)
{
return;
}
Children.Clear();
for (int x = 0; x < ActualWidth; x += width)
{
for (int y = 0; y < ActualHeight; y += height)
{
var image = new Image { Source = ImageSource };
Canvas.SetLeft(image, x);
Canvas.SetTop(image, y);
Children.Add(image);
}
}
Clip = new RectangleGeometry { Rect = new Rect(0, 0, ActualWidth, ActualHeight) };
}
}
@robfe
Copy link
Author

robfe commented Jun 27, 2012

yes it's this mental. An image won't have an accurate width & height until it's raised ImageOpened in winRT, which won't fire till it's added to the visual tree. I've never seen visual artifacts from this approach, but to be safe set a background with a similar tone to the image.

The tiles won't look good if scaled, either.

@Rickrat
Copy link

Rickrat commented Mar 6, 2013

To be able to use this in design mode, add a data template into a resource dictionary and load it with a contentpresenter.

Code:
http://pastebin.com/aA81Tqry

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