Scott Logic

Developing a (very) Lookless Silverlight Radial Gauge Control

August 19th, 2010
This blog post describes the development of a lookless radial gauge control. In this post I will explore the use of an attached view model in order to move view specific properties and logic out of the control code in order to give a truly lookless control. Today I had to get up far too early [...]

Exposing and Binding to a Silverlight ScrollViewer’s Scrollbars

July 21st, 2010
The Silverlight ScrollViewer exposes readonly properties which indicate the current vertical and horizontal scroll offset, and methods for setting the current offset. In this blog post I demonstrate a simple attached behaviour that exposes these offsets as read / write dependency properties allowing them to be bound to. The Silverlight ScrollViewer is a very useful control, [...]

A Universal Value Converter for WPF

July 9th, 2010
This post provides a simple IValueConverter implementation that makes use of the framework type converters in order to convert between a large range of source / target types. This converter can be used both within bindings and in code-behind to give more concise property setters. Introduction One of the great features of the XAML language is that [...]

Modal dialogs in cross-platform WPF/Silverlight applications

June 18th, 2010
This blog post looks at the problem of showing modal dialog windows in applications that target both the Silverlight and WPF platforms. A solution is provided which allows modal dialogs to be written that work well for both technologies. Silverlight is, roughly speaking, a subset of Windows Presentation Foundation (WPF). This means that it is possible [...]

Throttling Silverlight Mouse Events to Keep the UI Responsive

June 14th, 2010
If your Silverlight application performs intensive updates to the UI during mouse events, the UI can freeze because it is invalidated before it has a chance to render. This post describes a technique for ‘throttling’ mouse events to ensure that each time an event occurs, the UI has the opportunity to render. Introduction – the problem The [...]

Binding a Silverlight 3 DataGrid to dynamic data via IDictionary (Updated)

March 26th, 2010
In this post I demonstrate a method for binding a Silverlight 3 DataGrid to dynamic data, i.e. data which does not have properties that are known at design time. This technique results in a bound grid which is sortable and editable. This blog post is a bug fix (due to differences between SL2 and SL3) [...]

Linq to Visual Tree

March 4th, 2010
This blog post demonstrates a Linq API which can be used to query the WPF / Silverlight Visual Tree. You can find a few other Linq to Visual Tree techniques on other blogs, but what makes this one unique is that it retains, and allows queries that make use of the tree like structure rather [...]

Forcing Event Consumer Cleanup without Weak Events

February 19th, 2010
This blog post describes a simple technique for ensuring that consumers of events unsubscribe their event handlers without the need for weak events. I think the concept of managed memory, where the cleanup of unused objects from the heap is performed by a garbage collector, is a fantastic idea. It means that developers working with Java [...]

Rippling Reflection Effect with Silverlight 3’s WriteableBitmap

December 16th, 2009

This blog post demonstrates how Silvelight 3’s WriteableBitmap can be used to create a UserControl that renders the content of any other Framework Element as a reflection with an animated ripple effect

I was sad to hear the news earlier this year that Yahoo! was pulling the plug on GeoCities. Somewhere buried deep within GeoCities is the first web page I ever created, complete with “Under Construction” banner, animated GIFs, guestbooks, and nasty background music. Unfortunately, I have no idea what the URL for that page was, and this is long before Google ran my life!

This blog post is a tribute to one of the many dynamic effects that were popular in the 90’s, animated reflections. These Java applets were quite popular for a while, but have gone the same way as GeoCities. Perhaps it is time for a revival?

The Silverlight application shown above contains a UserControl which renders an animated reflection of a referenced FrameworkElement.

The code which produces the ripple is very simple, A DispatcherTimer increments _time and redraws the reflection. The reflection itself is achieved by constructing a WriteableBitmap from the referenced element, allowing us to grab its pixel values. Another WriteableBitmap is constructed for the reflection image, and rows of pixels are copied across with a suitable Y offset to produce the ripple effect:

private double _time = 0.0;
 
private void Timer_Tick(object sender, EventArgs e)
{
    // increment phi and update the reflection
    _time += 0.4;
    UpdateReflection();
}
 
/// <summary>
/// Copies an inverted image of the referenced FrameworkElement
/// with a 'ripple' effect
/// </summary>
private void UpdateReflection()
{
    FrameworkElement reflectedFE = ReflectedElement as FrameworkElement;
 
    if (reflectedFE == null)
        return;
 
    // synchronize the element width
    Width = reflectedFE.ActualWidth;
 
    // copy the source into a writeable bitmap
    WriteableBitmap sourceBitmap = new WriteableBitmap(reflectedFE, null);
 
    // create a target which is the same width / height as the reflection element
    WriteableBitmap targetBitmap = new WriteableBitmap((int)ActualWidth, (int)ActualHeight);
 
    // copy the reflection
    for (int y = 0; y < targetBitmap.PixelHeight; y++)
    {
        double amplitude = ComputeAmplitude(y, targetBitmap.PixelHeight);
        double sinusoid = ComputeRipple(y, targetBitmap.PixelHeight, _time);
 
        // the offset to the y value index caused by the ripple
        int yOffset = (int)(sinusoid * amplitude);
 
        // compute the Y position of the line to copy from the source image
        int sourceYLocation = sourceBitmap.PixelHeight - 1 -
            ((y + yOffset) * sourceBitmap.PixelHeight) / targetBitmap.PixelHeight;
 
        // check that this value is in range
        sourceYLocation = Math.Min(sourceBitmap.PixelHeight - 1, Math.Max(0, sourceYLocation));
 
        // copy the required row
        int sourceIndex = sourceYLocation * sourceBitmap.PixelWidth;
        int targetIndex = y * targetBitmap.PixelWidth;
        for (int i = 0; i < targetBitmap.PixelWidth; i++)
        {
            targetBitmap.Pixels[targetIndex++] = sourceBitmap.Pixels[sourceIndex++];
        }                
    }
 
    targetBitmap.Invalidate();
 
    LayoutRoot.Source = targetBitmap;
}
 
/// <summary>
/// Compute the amplitude of the oscillations at a given Y position
/// </summary>
private double ComputeAmplitude(int y, int height)
{
    // our amplitude range is 1 to 3
    return ((double)y * 2) / (double)height + 1.0;
}
 
/// <summary>
/// Compute the sinusoid applied to teh image at the given location
/// </summary>
private double ComputeRipple(int y, int height, double time)
{
    // provide a ripple that is the combination of two out of phase sine waves
    double phaseFactor = (double)y / (double)height;
    return Math.Sin(time + phaseFactor * 16) + Math.Sin(time + phaseFactor * 30)
        + Math.Sin(time + phaseFactor * 62);
}

The XAML for this user control is simply an image with an opacity gradient:

<UserControl x:Class="SilverlightShimmer.ReflectionControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="300" Height="300">
    <Image x:Name="LayoutRoot">
        <Image.OpacityMask>
            <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                <GradientStop Color="#FF000000" Offset="0"/>
                <GradientStop Color="#00000000" Offset="1"/>
            </LinearGradientBrush>
        </Image.OpacityMask>
    </Image>
</UserControl>

This control is associated with our Christmas-ey image as follows:

<UserControl x:Class="SilverlightShimmer.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:SilverlightShimmer" Width="320" Height="260">
 
    <Grid Background="Black">
 
        <StackPanel Orientation="Vertical" Margin="10">            
            <Border  x:Name="controlToReflect" BorderThickness="5" BorderBrush="LightGray"
                     CornerRadius="3" HorizontalAlignment="Center">
                <Image  Source="christmas.jpg" Margin="3"
                        Stretch="None"/>
            </Border>
            <local:ReflectionControl x:Name="shimmer" Height="80" Margin="3"
                       ReflectedElement="{Binding ElementName=controlToReflect}"/>
        </StackPanel>
    </Grid>
</UserControl>

One interesting point here is the way in which the Border and Image are associated with the ReflectionControl. The ReflectedElement property is bound to the Border via an ElementName binding, however this binding has no Path. Therefore, rather than binding to a property of the referenced element, the ReflectedElement is bound to the element itself. Hence, no need for any code behind to associated the ReflectionControl with the element(s) to render.

This control can be used to render a reflection of anything (even a reflection of a reflection if you so wish). Here is a more complex example:

You can download the full sourcecode here: SilverlightShimmer.zip

Regards, Colin E.

Helpful extension methods for Show / Hide animations in Silverlight

September 26th, 2009
Today’s blog post is a couple of very simple utility methods that I have found myself using again and again … The animations that Silverlight developers have at their disposal are both varied and powerful. It is easy to get carried away and cover your application with gratuitous animations, which soon become an unwanted distraction. However, [...]