Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ExImage -- A Silverlight control very similar to the Image control that supports image tiling

0.00/5 (No votes)
24 Jan 2010 1  
ExImage is a Silverlight control very similar to the built-in Image control, except it supports three more stretch modes: RepeatX, RepeatY, and RepeatXY, which means images can be tiled horizontally, vertically, or both.

Screen Capture

Introduction

ExImage is a Silverlight control very similar to the built-in Image control, except it supports three more stretch modes: RepeatX, RepeatY and RepeatXY. Which means an image can be tiled in horizontal direction, or vertical direction, or both.

Repeat in X Direction

Image repeat in x direction. The red part is the background.

Repeat in Y Direction

Image repeat in y direction. The red part is the background.

Repeat in both X and Y Direction

Image repeat in both x and y directions.

Background

In HTML, image background supports repeat x, repeat y, and repeat in both directions. But in Silverlight, the Image control only supports None, Fill, Uniform, and UniformFill stretch modes. And, you can't easily tile an image in x/y direction. So, I create the ExImage control to emulate the HTML background image behaviors and lets you easily use it.

Using the Code

It's very similar to the intrinsic Image control both in beahvor and in using the methods. First of all, you should add a reference to the Cokkiy.ExImage assembly to your Silverlight project.

Then, in your page's XAML file, you put it just like an Image control and set its Source and Stretch properties:

<cokkiy:ExImage x:Name="myImage" Source="s.jpg" 
  Stretch="RepeatX" Background="#FFDA2525" Width="400" Height="300"/>

How it Works

We all know that, in Silverlight, the only way to display an image is using the Image control, and there are no methods or functions to directly manipulate the image. So clearly, the only way to tile an image is using many Image controls and tiling them on the destination rectangle. And the end result will be just like tiling the image.

Now, let's look at how the RepeatX mode is implemented.

case ExStretch.RepeatX:
{
     int count = (int)Math.Ceiling(Container.ActualWidth / imgWidth);
     double totalUsedWidth = 0.0; //Already used Width
     double height = Math.Min(imgHeight, Container.ActualHeight);
     for (int i = 0; i < count; i++)
     {
          double remain = Container.ActualWidth - totalUsedWidth;
          Image img = new Image();
          img.Stretch = System.Windows.Media.Stretch.None;
          img.Width = remain >= imgWidth ? imgWidth : remain;
          img.Height = height;
          img.Source = Source;
          Canvas.SetLeft(img, imgWidth * i);
          Canvas.SetTop(img, 0);
          imagesList.Add(img);
          totalUsedWidth += imgWidth;
     }
}
break;

In the code, we first calculate the count, how many Image controls should be put in the x direction. Then, we create as many Image controls and set their left positions. We then save them to a list.

In the end, we add the Images that have been saved in the list to the Conatiner, which is a Canvas.

foreach (var item in imagesList)
{
     Container.Children.Add(item);
}

In the previous code, imgWidth and imgHeight means the real width and height of the image, which can be obtained from the BitmapSource object. The BitmapSource class has two properties, PixelHeight and PixelWidth, which represent the width and height of the image. But those properties only have a value when the image is loaded, so you need to handle the ImageOpened event to retrieve those values.

//Calc image real size
private void CalcImageSize(ImageSource imageSource)
{
    if (imageSource != null)
    {
        Image img = new Image();
        img.ImageOpened += new EventHandler<RoutedEventArgs>(img_ImageOpened);
        img.Source = imageSource;
        Container.Children.Clear();
        // If we don't add this image to the visual tree,
        // the image will never be loaded
        // so, the ImageOpened event will nerver happeded
        Container.Children.Add(img);
    }
}

void img_ImageOpened(object sender, RoutedEventArgs e)
{
    Image img = sender as Image;
    imgHeight = (img.Source as BitmapSource).PixelHeight;
    imgWidth = (img.Source as BitmapSource).PixelWidth;
    Container.Children.Remove(img); // remove this because we no need it
    img = null;
    CreateImage();
}

For more information about how to get the image's dimensions, you may read this Silverlight Tip of the Day #13 - How to Get an Image's Dimensions in Silverlight and these http://forums.silverlight.net/forums/t/14637.aspx articles.

History

  • 24 Jan 2010: Initial post.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here