Skip to content

Instantly share code, notes, and snippets.

@aloisdg
Forked from ngbrown/TileCanvas.cs
Last active August 29, 2015 14:15
Show Gist options
  • Save aloisdg/a743d7113a0189afec4b to your computer and use it in GitHub Desktop.
Save aloisdg/a743d7113a0189afec4b to your computer and use it in GitHub Desktop.
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)
return;
_lastActualSize = newSize;
Rebuild();
}
private static void ImageSourceChanged(DependencyObject o, DependencyPropertyChangedEventArgs args)
{
var self = (TileCanvas)o;
var src = self.ImageSource;
if (src == null) return;
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)
{
ManageImageEvent((Image)sender);
Children.Add(new TextBlock
{
Text = exceptionRoutedEventArgs.ErrorException.Message,
Foreground = new SolidColorBrush(Colors.Red)
});
}
private void ImageOnImageOpened(object sender, RoutedEventArgs routedEventArgs)
{
ManageImageEvent((Image)sender);
Children.Clear();
Rebuild();
}
private void ManageImageEvent(Image image)
{
image.ImageOpened -= ImageOnImageOpened;
image.ImageFailed -= ImageOnImageFailed;
}
private void Rebuild()
{
var bmp = ImageSource as BitmapSource;
if (bmp == null
|| bmp.PixelWidth == 0 || bmp.PixelHeight == 0
|| ActualWidth.Equals(0) || ActualHeight.Equals(0))
return;
double currentTiledWidth = -1;
double currentTiledHeight = -1;
foreach (var child in Children.Where(c => c is Image).Cast<Image>())
{
var childTop = GetTop(child);
var childLeft = GetLeft(child);
if (childLeft >= ActualWidth || childTop >= ActualHeight)
Children.Remove(child);
else
{
currentTiledWidth = Math.Max(childLeft, currentTiledWidth);
currentTiledHeight = Math.Max(childTop, currentTiledHeight);
}
}
for (var x = 0; x < ActualWidth; x += bmp.PixelWidth)
for (var y = 0; y < ActualHeight; y += bmp.PixelHeight)
if (x > currentTiledWidth || y > currentTiledHeight)
{
var image = new Image { Source = ImageSource };
SetLeft(image, x);
SetTop(image, y);
Children.Add(image);
}
Clip = new RectangleGeometry { Rect = new Rect(0, 0, ActualWidth, ActualHeight) };
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment