Silverlight 3 Writable Bitmaps

A very useful feature of Silverlight 3 is its ability to render any UI element to a Bitmap.  This capability is already used internally by Silverlight 3 to cache rendered controls but the possibilities extend much further than performance improvements.  In games programming for example if you need to create a reflection in a scene in real-time, this is now an easy task using the WritableBitmap class.


To start with we have a grid containing four cells.  The top-left cell is rendered as normal using a Button, TextBlock, TextBox and an Image that can be rotated.  The three remaining grid cells contain ContentControl elements with rotations applied to give the impression of reflection, the content property of these is set at runtime:

<UserControl x:Class="WritableBitmap.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="300">
    <Canvas x:Name="LayoutRoot">
        <Grid Canvas.Left="100" Canvas.Top="10" Background="White">
            <Grid.Resources>
                <Storyboard x:Name="RotateYStoryBoard">
                    <DoubleAnimation Storyboard.TargetName="rotation" Storyboard.TargetProperty="RotationY" From="0.0" To="360.0" Duration="0:0:10" RepeatBehavior="Forever" />
                </Storyboard>
            </Grid.Resources>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="200" />
                <ColumnDefinition />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <Grid x:Name="scene" Grid.Row="0" Grid.Column="0" Background="White">
                <Border CornerRadius="4" BorderBrush="#888888" BorderThickness="2">
                    <StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
                        <Button Content="Rotate Image" Width="100" Height="30" Margin="2" Click="Button_Click" />
                        <TextBlock Text="Some Text!" FontSize="16" Margin="2">
                    <TextBlock.Effect>
                        <DropShadowEffect ShadowDepth="4" />
                    </TextBlock.Effect>
                        </TextBlock>
                        <TextBox Width="100" Height="30" FontSize="18" Margin="2" />
                        <Image Source="Sydney.JPG" Width="100" Margin="2">
                            <Image.Projection>
                                <PlaneProjection x:Name="rotation" />
                            </Image.Projection>
                        </Image>
                    </StackPanel>
                </Border>
            </Grid>
            <Grid Grid.Row="0" Grid.Column="1">
                <Grid.Projection>
                    <PlaneProjection RotationY="180" />
                </Grid.Projection>
                <ContentControl x:Name="reflection1" Opacity="0.6" />
                <Rectangle Fill="#20ff0000" />
            </Grid>
            <Grid Grid.Row="1" Grid.Column="0">
                <Grid.Projection>
                    <PlaneProjection RotationX="180" />
                </Grid.Projection>
                <ContentControl x:Name="reflection2" Opacity="0.6" />
                <Rectangle Fill="#2000ff00" />
            </Grid>
            <Grid Grid.Row="1" Grid.Column="1">
                <Grid.Projection>
                    <PlaneProjection RotationX="180" RotationY="180" />
                </Grid.Projection>
                <ContentControl x:Name="reflection3" />
                <Rectangle Fill="#200000ff" />
            </Grid>
        </Grid>
    </Canvas>
</UserControl>


The C# simply contains the Click event to handle the image rotation, the interesting part is the use of the WritableImage class to render the UI Element scene to a static bitmap:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace WritableBitmap
{
    public partial class MainPage : UserControl
    {
        private DispatcherTimer _timer = new DispatcherTimer();
        private WriteableBitmap _reflectedImage = new WriteableBitmap(200, 100, PixelFormats.Bgr32);

        public MainPage()
        {
            InitializeComponent();

            _timer.Interval = new TimeSpan(0, 0, 0, 0, 20);
            _timer.Tick += new EventHandler(Tick);
            _timer.Start();
        }

        protected void Tick(object sender, EventArgs e)
        {
            _reflectedImage = new WriteableBitmap((int)scene.RenderSize.Width, (int)scene.RenderSize.Height, PixelFormats.Bgr32);

            _reflectedImage.Render(scene, new TranslateTransform());

            reflection1.Content = new Image() { Source = _reflectedImage };
            reflection2.Content = new Image() { Source = _reflectedImage };
            reflection3.Content = new Image() { Source = _reflectedImage };
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            RotateYStoryBoard.Begin();
        }
    }
}


We use a DispatcherTimer that frequently calls the Tick() method, and in this method we create our WritableBitmap instance and call its Render method which simply converts any UI Element into a bitmap.  We then set the source of our three reflected ContentControl elements to this bitmap.

Rendering UI Elements to bitmaps is a simple but powerful addition to Silverlight and opens up a host of new applications such as graphic packages and as already mentioned special effects in games.

Post your Comments

Post your Comments

 
Latest Games
Zombie Escape
Apr 19, 2016
Plays: 1,404

Zombie Escape ScreenshotDrive fast before the crazy mutant zombies get you!

6 Ratings/4.1 Average
Car Parking
Jan 16, 2016
Plays: 1,371

Car Parking ScreenshotGuide the car to its parking space in this fun Car Parking game.

1 Rating/5 Average
Trash It
Jan 11, 2016
Plays: 1,257

Trash It ScreenshotAim for the Trash Can and get the various items of Trash in the bin.

4 Ratings/5 Average
Sky Fly
Jan 11, 2016
Plays: 1,377

Sky Fly ScreenshotFly your plane in this colorful vertical scrolling shoot-em-up. Blast the bad guys and collect any bonus's they leave behind.

1 Rating/5 Average
Professor Snappy
Jan 11, 2016
Plays: 1,010

Professor Snappy ScreenshotPop as many bubbles as possible in this fun and colorful bubble popping game. The levels start off easy enough but gradually get harder!

1 Rating/5 Average
Monster Match Saga
Jan 10, 2016
Plays: 1,342

Monster Match Saga ScreenshotHere we have a bunch of monsters that need to be matched up. Look out for the bomb and spinning monsters that will cause special damage!

3 Ratings/4.6 Average
Fly Bird Fly
Jan 10, 2016
Plays: 1,063

Fly Bird Fly ScreenshotGuide your friendly Bird through the maze of pipes and other obstacles collecting the Stars in this cool arcade game inspired by the legendary Flappy Bird.

1 Rating/5 Average
Life In One
Jan 10, 2016
Plays: 1,258

Life In One ScreenshotYou are stranded on an Alien planet. Your goal is to build a space rocket and escape. Start by building units to create power and mine the metal patches. Build defenses to defend your base from the advancing Aliens and Zombies!

2 Ratings/3 Average
X Pool
Jan 02, 2016
Plays: 1,762

X Pool ScreenshotPlay Pool against the computer or battle against your friends in the online mode!

3 Ratings/3 Average
Fruit Slicer
Jan 02, 2016
Plays: 1,022

Fruit Slicer ScreenshotSlice the fruit that is thrown up onto the screen. Slice the fruit into multiple pieces for maximum points!

1 Rating/5 Average