Scott Logic

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 than simply flattening it.

I have recently published an article on codeproject which describes a technique for generating Linq API for querying tree-like structures. This blog post makes use of a generated API for WPF / Silverlight. If you are interested in the more generic approach, and how this API was constructed, (and how it is influenced by XPath) head on over to codeproject …

What I will provide here is a brief overview of the Linq to Visual Tree API. The full sourcecode for this API is at the end of this article.

The Linq to Visual Tree API defines a number of extension methods on DependencyObject that provide mechanisms for navigating to other DependencyObject instances. I will provide a few examples that query the following simple markup:

<Grid x:Name="GridOne" Background="White">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
 
    <TextBox x:Name="TextBoxOne" Text="One" Grid.Row="0" />
 
    <StackPanel x:Name="StackPanelOne" Grid.Row="1">
        <TextBox x:Name="TextBoxTwo" Text="Two" />
 
        <Grid x:Name="GridTwo">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
 
            <TextBox x:Name="TextBoxThree" Text="Three" Grid.Row="0" />
 
            <StackPanel x:Name="StackPanelTwo" Grid.Row="1">
                <TextBox x:Name="TextBoxFour" Text="Four"/>                    
            </StackPanel>
        </Grid>
    </StackPanel>
</Grid>

We’ll start with a simple example. Include the Linq to Visual Tree namespace, then use the Descendants method to obtain all the descendants (i.e. children and children’s children, etc …) of an object within the
visual tree.

Descendants

using LinqToVisualTree;
 
// all items within the visual tree
IEnumerable<DependencyObject> allDescendants = this.Descendants();
/*
gives ...
0 {Grid} 	[GridOne]
1 {TextBox} 	[TextBoxOne]
2 {StackPanel} 	[StackPanelOne]
3 {TextBox} 	[TextBoxTwo]
4 {Grid} 	[GridTwo]
5 {TextBox} 	[TextBoxThree]
6 {StackPanel} 	[StackPanelTwo]
7 {TextBox} 	[TextBoxFour]
*/
 
// all items within the visual tree of 'GridTwo'
var descendantsOfGridTwo = GridTwo.Descendants();
/*
gives ...
0 {TextBox} 	[TextBoxThree]
1 {StackPanel} 	[StackPanelTwo]
2 {TextBox} 	[TextBoxFour]
*/

Each of the extension methods also has a corresponding method with a generic type parameter that filters the collection to find elements of a specific type:

// all items within the visual tree of 'GridTwo' that are textboxes
var textBoxDescendantsOfGridTwo = GridTwo.Descendants()
                                         .Where(i => i is TextBox);
/*
0 {TextBox} 	[TextBoxThree]
1 {TextBox} 	[TextBoxFour]
*/
 
// a shorthand using the generic version of Descendants
var textBoxDescendantsOfGridTwo2 = GridTwo.Descendants<TextBox>();
/*
0 {TextBox} 	[TextBoxThree]
1 {TextBox} 	[TextBoxFour]
*/

Elements

The elements extension method obtains all the direct children of an item in the visual tree:

// find all direct children of this user control 
var userControlChildren = this.Elements();
/*
0 {Grid} 	[GridOne]
*/
 
// find all direct children of the grid 'GridTwo'
var gridChildren = GridTwo.Elements();
/*
0 {TextBox} 	[TextBoxThree]
1 {StackPanel} 	[StackPanelTwo]
*/
 
// find all direct children of the grid 'GridTwo' that are StackPanels
var gridChildren2 = GridTwo.Elements<StackPanel>();
/*
0 {StackPanel} 	[StackPanelTwo]
*/

There are also, ElementsBeforeSelf and ElementsAfterSelf methods that return the elements before and after the item which the method is being invoked upon.

Ancestors

The ancestors methods traverse the tree towards the root, finding all the ancestors:

// the ancestors for 'TextBoxFour'
var ancestors = TextBoxFour.Ancestors();
/*
0 {StackPanel} 	[StackPanelTwo]
1 {Grid} 	[GridTwo]
2 {StackPanel} 	[StackPanelOne]
3 {Grid} 	[GridOne]
4 {MainPage} 	[]
*/
 
// the ancestors for 'TextBoxFour' that are StackPanels
var stackPanelAncestors = TextBoxFour.Ancestors<StackPanel>();
/*
0 {StackPanel} 	[StackPanelTwo]
1 {StackPanel} 	[StackPanelOne]
*/

Putting it all together

The Linq to Tree API not only defines extension methods on DependencyObject, but also the same extension methods on IEnumerable<DependencyObject>. Unless you have previous experience of Linq to XML, I would strongly suggest reading my codeproject article to understand how this works!

This allows you to form much more complex queries. For example, you can find all TextBoxs that have a Grid as a direct parent:

var itemsFluent = this.Descendants<TextBox>()
                      .Where(i => i.Ancestors().FirstOrDefault() is Grid);
 
var itemsQuery = from v in this.Descendants<TextBox>()
                 where v.Ancestors().FirstOrDefault() is Grid
                 select v;
/*
0 {TextBox} 	[TextBoxOne]
1 {TextBox} 	[TextBoxThree]
*/

Here, you can also see we are mixing the fluent and query syntax for Linq. Both give the same result.

The next example finds all StackPanels that are within another StackPanels visual tree:

var items2Fluent = this.Descendants<StackPanel>()
                              .Descendants<StackPanel>();
 
var items2Query = from i in
                      (from v in this.Descendants<StackPanel>()
                       select v).Descendants<StackPanel>()
                  select i;
/*
0 {StackPanel} 	[StackPanelTwo]
*/

Finally, this one-liner, outputs the entire visual tree in ASCII! It makes use of the DescendantsAndSelf, Ancestors and ElementsBeforeSelf methods, plus the funky Linq Aggregate method.

string tree = this.DescendantsAndSelf().Aggregate("",
    (bc, n) => bc + n.Ancestors().Aggregate("", (ac, m) => (m.ElementsAfterSelf().Any() ? "| " : "  ") + ac,
    ac => ac + (n.ElementsAfterSelf().Any() ? "+-" : "\\-")) + n.GetType().Name + "\n");
\-MainPage
  \-Grid
    +-TextBox
    | \-Grid
    |   +-Border
    |   | \-Grid
    |   |   +-Border
    |   |   \-Border
    |   |     \-ScrollViewer
    |   |       \-Border
    |   |         \-Grid
    |   |           +-ScrollContentPresenter
    |   |           | \-TextBoxView
    |   |           +-Rectangle
    |   |           +-ScrollBar
    |   |           \-ScrollBar
    |   +-Border
    |   +-Border
    |   \-Border
    |     \-Grid
    |       +-Path
    |       \-Path
    \-StackPanel
      +-TextBox
      | \-Grid
      |   +-Border
      |   | \-Grid
      |   |   +-Border
      |   |   \-Border
      |   |     \-ScrollViewer
      |   |       \-Border
      |   |         \-Grid
      |   |           +-ScrollContentPresenter
      |   |           | \-TextBoxView
      |   |           +-Rectangle
      |   |           +-ScrollBar
      |   |           \-ScrollBar
      |   +-Border
      |   +-Border
      |   \-Border
      |     \-Grid
      |       +-Path
      |       \-Path
      \-Grid
        +-TextBox
        | \-Grid
        |   +-Border
        |   | \-Grid
        |   |   +-Border
        |   |   \-Border
        |   |     \-ScrollViewer
        |   |       \-Border
        |   |         \-Grid
        |   |           +-ScrollContentPresenter
        |   |           | \-TextBoxView
        |   |           +-Rectangle
        |   |           +-ScrollBar
        |   |           \-ScrollBar
        |   +-Border
        |   +-Border
        |   \-Border
        |     \-Grid
        |       +-Path
        |       \-Path
        \-StackPanel
          \-TextBox
            \-Grid
              +-Border
              | \-Grid
              |   +-Border
              |   \-Border
              |     \-ScrollViewer
              |       \-Border
              |         \-Grid
              |           +-ScrollContentPresenter
              |           | \-TextBoxView
              |           +-Rectangle
              |           +-ScrollBar
              |           \-ScrollBar
              +-Border
              +-Border
              \-Border
                \-Grid
                  +-Path
                  \-Path

Note: this was invoked after the LayoutUpdated event so that we not only see the elements from our XAML, but also the elements created from their templates, giving us our full run-time visual tree.

You can download a simple Silverlight application that demonstrated all the examples given above:
LinqToTree.zip.

Or, if you just want the Linq to VisualTree code, you can copy-n-paste from the windows below which has the entire API, which includes the methods illustrated above,, plus their IEnumerable equivalents, and a few others I have not illustrated.

using System;
using System.Linq;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;

namespace LinqToVisualTree
{
    /// 
    /// Adapts a DependencyObject to provide methods required for generate
    /// a Linq To Tree API
    /// 
    public class VisualTreeAdapter : ILinqTree
    {
        private DependencyObject _item;

        public VisualTreeAdapter(DependencyObject item)
        {
            _item = item;
        }

        public IEnumerable Children()
        {
            int childrenCount = VisualTreeHelper.GetChildrenCount(_item);
            for (int i = 0; i < childrenCount; i++)
            {
                yield return VisualTreeHelper.GetChild(_item, i);
            }
        }

        public DependencyObject Parent
        {
            get
            {
                return VisualTreeHelper.GetParent(_item);
            }
        }
    }
}

namespace LinqToVisualTree
{
    /// 
    /// Defines an interface that must be implemented to generate the LinqToTree methods
    /// 
    /// 
    public interface ILinqTree
    {
        IEnumerable Children();

        T Parent { get; }
    }

    public static class TreeExtensions
    {
        /// 
        /// Returns a collection of descendant elements.
        /// 
        public static IEnumerable Descendants(this DependencyObject item)
        {
            ILinqTree adapter = new VisualTreeAdapter(item);
            foreach (var child in adapter.Children())
            {
                yield return child;

                foreach (var grandChild in child.Descendants())
                {
                    yield return grandChild;
                }
            }
        }

        /// 
        /// Returns a collection containing this element and all descendant elements.
        /// 
        public static IEnumerable DescendantsAndSelf(this DependencyObject item)
        {
            yield return item;

            foreach (var child in item.Descendants())
            {
                yield return child;
            }
        }

        /// 
        /// Returns a collection of ancestor elements.
        /// 
        public static IEnumerable Ancestors(this DependencyObject item)
        {
            ILinqTree adapter = new VisualTreeAdapter(item);

            var parent = adapter.Parent;
            while (parent != null)
            {
                yield return parent;
                adapter = new VisualTreeAdapter(parent);
                parent = adapter.Parent;
            }
        }

        /// 
        /// Returns a collection containing this element and all ancestor elements.
        /// 
        public static IEnumerable AncestorsAndSelf(this DependencyObject item)
        {
            yield return item;

            foreach (var ancestor in item.Ancestors())
            {
                yield return ancestor;
            }
        }

        /// 
        /// Returns a collection of child elements.
        /// 
        public static IEnumerable Elements(this DependencyObject item)
        {
            ILinqTree adapter = new VisualTreeAdapter(item);
            foreach (var child in adapter.Children())
            {
                yield return child;
            }
        }

        /// 
        /// Returns a collection of the sibling elements before this node, in document order.
        /// 
        public static IEnumerable ElementsBeforeSelf(this DependencyObject item)
        {
            if (item.Ancestors().FirstOrDefault() == null)
                yield break;
            foreach (var child in item.Ancestors().First().Elements())
            {
                if (child.Equals(item))
                    break;
                yield return child;
            }
        }

        /// 
        /// Returns a collection of the after elements after this node, in document order.
        /// 
        public static IEnumerable ElementsAfterSelf(this DependencyObject item)
        {
            if (item.Ancestors().FirstOrDefault() == null)
                yield break;
            bool afterSelf = false;
            foreach (var child in item.Ancestors().First().Elements())
            {
                if (afterSelf)
                    yield return child;

                if (child.Equals(item))
                    afterSelf = true;
            }
        }

        /// 
        /// Returns a collection containing this element and all child elements.
        /// 
        public static IEnumerable ElementsAndSelf(this DependencyObject item)
        {
            yield return item;

            foreach (var child in item.Elements())
            {
                yield return child;
            }
        }

        /// 
        /// Returns a collection of descendant elements which match the given type.
        /// 
        public static IEnumerable Descendants(this DependencyObject item)
        {
            return item.Descendants().Where(i => i is T).Cast();
        }

        /// 
        /// Returns a collection of the sibling elements before this node, in document order
        /// which match the given type.
        /// 
        public static IEnumerable ElementsBeforeSelf(this DependencyObject item)
        {
            return item.ElementsBeforeSelf().Where(i => i is T).Cast();
        }

        /// 
        /// Returns a collection of the after elements after this node, in document order
        /// which match the given type.
        /// 
        public static IEnumerable ElementsAfterSelf(this DependencyObject item)
        {
            return item.ElementsAfterSelf().Where(i => i is T).Cast();
        }

        /// 
        /// Returns a collection containing this element and all descendant elements
        /// which match the given type.
        /// 
        public static IEnumerable DescendantsAndSelf(this DependencyObject item)
        {
            return item.DescendantsAndSelf().Where(i => i is T).Cast();
        }

        /// 
        /// Returns a collection of ancestor elements which match the given type.
        /// 
        public static IEnumerable Ancestors(this DependencyObject item)
        {
            return item.Ancestors().Where(i => i is T).Cast();
        }

        /// 
        /// Returns a collection containing this element and all ancestor elements
        /// which match the given type.
        /// 
        public static IEnumerable AncestorsAndSelf(this DependencyObject item)
        {
            return item.AncestorsAndSelf().Where(i => i is T).Cast();
        }

        /// 
        /// Returns a collection of child elements which match the given type.
        /// 
        public static IEnumerable Elements(this DependencyObject item)
        {
            return item.Elements().Where(i => i is T).Cast();
        }

        /// 
        /// Returns a collection containing this element and all child elements.
        /// which match the given type.
        /// 
        public static IEnumerable ElementsAndSelf(this DependencyObject item)
        {
            return item.ElementsAndSelf().Where(i => i is T).Cast();
        }

    }

    public static class EnumerableTreeExtensions
    {
        /// 
        /// Applies the given function to each of the items in the supplied
        /// IEnumerable.
        /// 
        private static IEnumerable DrillDown(this IEnumerable items,
            Func> function)
        {
            foreach (var item in items)
            {
                foreach (var itemChild in function(item))
                {
                    yield return itemChild;
                }
            }
        }

        /// 
        /// Applies the given function to each of the items in the supplied
        /// IEnumerable, which match the given type.
        /// 
        public static IEnumerable DrillDown(this IEnumerable items,
            Func> function)
            where T : DependencyObject
        {
            foreach (var item in items)
            {
                foreach (var itemChild in function(item))
                {
                    if (itemChild is T)
                    {
                        yield return (T)itemChild;
                    }
                }
            }
        }

        /// 
        /// Returns a collection of descendant elements.
        /// 
        public static IEnumerable Descendants(this IEnumerable items)
        {
            return items.DrillDown(i => i.Descendants());
        }

        /// 
        /// Returns a collection containing this element and all descendant elements.
        /// 
        public static IEnumerable DescendantsAndSelf(this IEnumerable items)
        {
            return items.DrillDown(i => i.DescendantsAndSelf());
        }

        /// 
        /// Returns a collection of ancestor elements.
        /// 
        public static IEnumerable Ancestors(this IEnumerable items)
        {
            return items.DrillDown(i => i.Ancestors());
        }

        /// 
        /// Returns a collection containing this element and all ancestor elements.
        /// 
        public static IEnumerable AncestorsAndSelf(this IEnumerable items)
        {
            return items.DrillDown(i => i.AncestorsAndSelf());
        }

        /// 
        /// Returns a collection of child elements.
        /// 
        public static IEnumerable Elements(this IEnumerable items)
        {
            return items.DrillDown(i => i.Elements());
        }

        /// 
        /// Returns a collection containing this element and all child elements.
        /// 
        public static IEnumerable ElementsAndSelf(this IEnumerable items)
        {
            return items.DrillDown(i => i.ElementsAndSelf());
        }

        /// 
        /// Returns a collection of descendant elements which match the given type.
        /// 
        public static IEnumerable Descendants(this IEnumerable items)
            where T : DependencyObject
        {
            return items.DrillDown(i => i.Descendants());
        }

        /// 
        /// Returns a collection containing this element and all descendant elements.
        /// which match the given type.
        /// 
        public static IEnumerable DescendantsAndSelf(this IEnumerable items)
            where T : DependencyObject
        {
            return items.DrillDown(i => i.DescendantsAndSelf());
        }

        /// 
        /// Returns a collection of ancestor elements which match the given type.
        /// 
        public static IEnumerable Ancestors(this IEnumerable items)
            where T : DependencyObject
        {
            return items.DrillDown(i => i.Ancestors());
        }

        /// 
        /// Returns a collection containing this element and all ancestor elements.
        /// which match the given type.
        /// 
        public static IEnumerable AncestorsAndSelf(this IEnumerable items)
            where T : DependencyObject
        {
            return items.DrillDown(i => i.AncestorsAndSelf());
        }

        /// 
        /// Returns a collection of child elements which match the given type.
        /// 
        public static IEnumerable Elements(this IEnumerable items)
            where T : DependencyObject
        {
            return items.DrillDown(i => i.Elements());
        }

        /// 
        /// Returns a collection containing this element and all child elements.
        /// which match the given type.
        /// 
        public static IEnumerable ElementsAndSelf(this IEnumerable items)
            where T : DependencyObject
        {
            return items.DrillDown(i => i.ElementsAndSelf());
        }
    }
}

Regards, Colin E.

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 or C# (or other CLR languages) can often forget all about memory allocation, concentrating on more interesting tasks. However, whereas in the Java language the concept of memory leaks has almost completely vanished, they unfortunately rear their ugly head all to often when developing applications for the Microsoft Common Language Runtime (CLR). This is almost entirely down to one thing, events.

The problem with events is that they form a strong reference (i.e. a link between two object instances that prohibits garbage collection) in a manner that is not immediately obvious due to the syntax that event subscription uses. When subscribing to an event, the following syntax is used:

// subscribe to an event
textBox.TextChanged += new EventHandler(TextBox_TextChanged);
// or
textBox.TextChanged += TextBox_TextChanged;
 
// remove the subscription
textBox.TextChanged -= new EventHandler(TextBox_TextChanged);
// or
textBox.TextChanged -= TextBox_TextChanged;

Note the second examples use the shortened syntax where the delegate instance, EventHandler, is not explicitly constructed but added by the compiler, there is no difference semantically.

By subscribing to an event the following relationships are constructed, with the direction of reference as indicated:

As you can see from the above, adding an handler to an event creates a strong reference from source to listener. This does not cause significant problems if the listener has a shorter or the same lifecycle that the source, as is the case where you add event handlers for controls in a Windows Form for example. However, if the source has a longer lifecycle than the listener, and the listener fails to remove its event subscription, a memory leak will occur.

In practice this kind of problem often occurs in modular applications where there exists some sort of Shell or Environment that raises events or acts as a mediator. Within this hosting environment their exists numerous loosely coupled modules which by necessity have a shorter lifecycle than their container. If a module subscribes to events from the Shell but fails to unsubscribe at the end of its life a memory leak occurs. In complex systems this happens surprisingly often!

A common solution to this problem is to use Weak Events. These are events where either the reference between source and listener is weak, meaning that listener can be garbage collected if it is only referenced via this event handler. An early implementation of this pattern was developed for WPF and is provided by Greg Schechter on his blog. There is also an excellent codeproject article by Daniel Grunwald which details many different approaches to creating weak event listeners and sources.

However, whilst liberally sprinkling weak events about your code will solve potential memory leaks, it should not be used as a replacement for proper event subscription clean-up. What if a module’s event handler performs non-trivial logic? Do you really want this to occur after the module is supposed to have been destroyed? So, how do you ensure that events are being unsubscribed? This can be done by code-review, or by making use of heap profiling tools such as dotTrace. With these tools you can run your application, create and destroy modules, garbage collect then inspect your heap to see that the modules and their related objects have been removed. If not, you can trace the object references to find the offending event handler. However, this is a time consuming process.

An alternative is to make use of the fact that events are simply delegates with a highly restrictive interface applied. However, within the class where the event is defined you can treat it as an delegate, allowing you to inspect its invocation list to find all the event handlers. Therefore, if you have a long-lived service component that raises events which are handled by shorter lived modules, you can check the event invocation list after all the modules have been destroyed at application shutdown to ensure that all modules have correctly unsubscribed. This can be achieved as follows:

/// <summary>
/// An event which indicates that some stock price has changed
/// </summary>
public event EventHandler<StockPriceUpdateEventArgs> StockPriceUpdate;
 
public void Dispose(object sender, EventArgs e)
{
    // check that when this service is destroyed, that there are no event
    // subscriptions
    CheckEventHasNoSubscribers(StockPriceUpdate);
}
 
/// <summary>
/// Detects whether an event has any subscribers
/// </summary>
[Conditional("DEBUG")]
private void CheckEventHasNoSubscribers(Delegate eventDelegate)
{
    if (eventDelegate != null)
    {
        // if the event has any subscribers, create an informative error message.
        if (eventDelegate.GetInvocationList().Length != 0)
        {
            int subscriberCount = eventDelegate.GetInvocationList().Length;
 
            // determine the consumers of this event
            StringBuilder subscribers = new StringBuilder();
            foreach (Delegate del in eventDelegate.GetInvocationList())
            {
                subscribers.Append((subscribers.Length != 0 ? ", " : "") + del.Target.ToString());
            }
 
            // name and shame them!
            Debug.WriteLine(string.Format("Event: {0} still has {1} subscribers, with the following targets [{2}]",
                eventDelegate.Method.Name, subscriberCount, subscribers.ToString()));
        }
    }
}

Here we have an event which our service raises, on disposal we check that the event has no subscribers. If any modules have failed to cleanup properly we see the following message:

Event: PriceService_StockPriceUpdate still has 2 subscribers, with the following targets:
[MemoryLeakExamples.StockPriceViewer, Text: StockPriceViewer,
MemoryLeakExamples.StockPriceViewer, Text: StockPriceViewer]

This message tells us how many classes still have referenced event handlers, and their type. This should make it very easy to pinpoint the memory leak.

The sourcecode for this blog post includes a very simple WinForms application where a Stock Price service raises events that are handled by simple UI modules that can be created and destroyed by the user. Run it in DEBUG mode to see the memory leaks! Look in StockPriceViewer to see how to fix the problem.

Download the sourcecode: MemoryLeakExample.zip

Regards, Colin E.

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, [...]

Declarative Dependency Property Definition with T4 + DTE

August 18th, 2009
This blog post describes a technique for specifying WPF / Silverlight Dependency Properties declaritively via attributes as illustrated by the following example: [DependencyPropertyDecl("Maximum", typeof(double), 0.0)] [DependencyPropertyDecl("Minimum", typeof(double), 0.0)] public partial class RangeControl : UserControl { ... } At design-time the declarations are read via a T4 template and the required code is generated. For more information, read on [...]

The mini-ViewModel pattern

August 7th, 2009
The construction of a ViewModel is often seen as the standard technique for solving binding problems within WPF and Silverlight. However, the addition of a ViewModel adds complexity to your code. This post describes an alternative method where a mini-ViewModel is applied directly to the problem areas in the view, leaving the rest to use [...]

Silverlight MultiBindings, How to attached multiple bindings to a single property.

June 25th, 2009
This blog posts describes a technique for associating multiple bindings with a single dependency property within Silverlight applications. WPF already has this functionality in the form of MultiBindings, the code in this post emulates this function. The simple application below demonstrates this technique, where there are three data-entry text boxes bound to the individual properties of [...]

Exposing Bindings as Properties of a Control

June 19th, 2009
I must admit that the title of this post is not entirely clear, however I couldn’t find a way to sum up the content in one short sentence, so we’ll dive straight into an example. Let’s say for example you have developed a funky little business-card as illustrated above, using the simple XAML below: <Border BorderBrush="LightGray" [...]

Dependency Property Performance and Lissajous Figures

June 2nd, 2009
A few night ago I was working on a Siverlight control which renders some quite complex Paths, the geometry of which is determined from a number of dependency properties. In order to gain UI coolness points I wanted to animate the dependency properties in order to see a smooth transition of the Path [...]

Silverlight ClipToBounds – Can I Clip It?, Yes You Can!

May 12th, 2009
With Silverlight, Panels do not clip their contents by default. See the following example: Where we have a Grid containing another Grid which itself contains an ellipse, and a Canvas which contains an ellipse: <Grid x:Name="LayoutRoot" Background="White"> <Grid.ColumnDefinitions> <ColumnDefinition Width="*"/> [...]