Jun 18
Reflecting on Reflections
icon1 roland | icon2 WPF | icon4 06 18th, 2008| icon35 Comments »

Lately both Apple and Microsoft user experience designers have been making user interfaces including beautiful reflection effects. Creating reflections in WPF is fairly easy to do, albeit repetitive. Luckily for us, a few people have created controls to simplify the process of adding reflections to our WPF applications.

Nir Dobovizki provides this implementation allowing a developer or designer to add his custom reflection control to a window as a single-child container of whatever element you want to display a reflection for. A beautiful reflection is then displayed below the contained element.

Grant Hinkson is the Director of Visual Design at Infragistics. And deservedly so. If you’ve used Pistachio or seen his Podder skin you know the guy’s got mad design skillz. Grant offers a control for download allowing a developer or designer to drop the control in a window and bind a ReflectionTarget property to any FrameworkElement. Unlike Nir’s control, you don’t wrap an element, you target it by setting it as the ReflectionTarget of Grant’s control and it displays a pretty reflection. I’m probably using it incorrectly because I don’t believe it automagically appears beneath the targeted element. I believe you have to set that up yourself, which is easy enough to do, just group the ReflectionTarget element and the reflector control together in a vertical StackPanel and you have a pretty reflection below the targeted element anytime you need it.

As Grant puts it:

If you want to tweak the reflection, you can always edit the ControlTemplate in Blend, but the default settings should cover most cases.

So there you go: two implementations offered for free to simplify adding this fancy schmancy visualization to your user experiences. The book on creating reflections with WPF is closed, right? Forrest Gump might say, “…that’s all I’ve got to say about that.”

But wait, there’s more! In this post I offer my own solution.

WTF?!

If it ain’t broke, don’t fix it, right?!

Well…sort of.

As an architect, I can be a bit obsessive compulsive with code I write for my own personal projects. It’s typically my downfall and prevents me from completing even the most simple projects. I overarchitect when it’s my own code and I get stuck in refactoring turmoil until I lose interest in the project. It’s just that sometimes things strike me as just plain wrong. In this case, looking at Nir or Grant’s control code in my XAML just feels wrong, architecturally speaking.
From a functional point of view, both solutions work just fine and get the job done but the following sections outline why it rubs me the wrong way:

What’s a Reflection?

Let’s talk for a moment on what a real life physical reflection is. It’s something, depending on the right circumstances, a physical object has. A physical object has a reflection. A reflection doesn’t have an object.

Nir’s reflection control has a contained element. Grant’s reflection control target’s another element. It has a target. Huh? You see, I tend to think in object-oriented terms and looking at the XAML using each of these controls doesn’t make sense to me. I just don’t see a reflection as a self-contained control acting upon a seperate control. Rather, I see a reflection as an attribute an existing element already has that can be enabled by the developer or designer at will.

What’s a Control?

Also, it just doesn’t fit my definition of a WPF control. I see a WPF control as an object that contains some data, it may provide a default view of the data, i.e. - a default control template, but ultimately a control is lookless, meaning it can take the shape of whatever the user experience designer chooses. Both Nir and Grant’s controls are completely customizable by overwriting their control templates. This just doesn’t make sense to me. A reflection is already a visualization of a real world object, not an abstract concept like a textbox or window. A reflection may have modifiable attributes to alter it’s appearance but one shouldn’t have to re-write the control template simply to change the opacity of the opacity mask. You wouldn’t change a reflection control’s template to make it look like a puppy dog, for example, because that’s not what a reflection is. If modifications need to be made to the characteristics of a reflection, those modifiable characteristics should be protected via encapsulation and exposed appropriately.

Fine, So What’s the Solution?

Assuming you agree with my logic about reflections and controls, how can we architect a solution that models what we’re thinking allowing us to have the same ease of of use as Nir and Grant’s solution, if not easier?

Our requirements are thus:

  • Must allow any FrameworkElement to display it’s own reflection when asked to.
  • Must allow simple means for the designer/developer to ask any element to display it’s reflection.
  • Must protect and expose some characteristics to allow customization of an element’s reflection.

Here’s what it looks like:

What can we use when we want to attach custom behaviors to any element in WPF? Attached properties should be popping into your head if they haven’t already.

So, my solution is composed of a simple class, to be punny, I’ll call it EyeCandy. The EyeCandy class exposes a boolean attached property called ShowMyReflection. To use the property in your page you simply add a namespace to your page:

Then to ask an element to display its reflection you simply do the following on the element of your choice:

…and you magically get this:

Simple, eh?

We can also set some additional properties to customize the reflection, also exposed as attached properties. The source code provides a sample window with various elements displaying their reflections. One of them has the customizable properties bound to sliders and a checkbox to show the effects of each:

What’s Going On Behind the Curtain?

Ok, so how does this work? The solution is fairly simple. We’re doing in code what we normally do in XAML or what Nir or Grant’s code does for us in their controls. When we want to make a reflection in XAML we normally do the following:

Create a vertical stackpanel, add the control we want to reflect and some other control, like a border or rectangle below to display the reflection on. Set the fill or background of the reflection element to a visual brush displaying the target element as it’s Visual property. Transform the visual brush to turn it upside down and then apply an Opacity Mask to the reflection element of a linear gradient to make the reflection appear to fade away. To make the reflection element match the size of target element, we bind it’s height/width to the target element’s actual size.

If that doesn’t make sense, have a look at this to see what we need to do programmatically.

From here on out, you’ll need to download the code to see most of the details. I originally had most of the code pasted in this post but it was really slowing down the load time of the page so I’ll just describe what’s going on and you can have a look at the downloadable source to see specifics.

So as mentioned previously, we’ve created an attached property called ShowMyReflection.

When the value is set to true, we simply remove the target element from it’s parent and store a reference to both. Then we create a stackpanel and add the target element to the stackpanel.

Then we create a Rectangle with the appropriate visual brush, opacity mask and layout bindings.

We expose a few other attached properties to customize the reflection and bind the values to various properties of the reflection element. These can be seen in the source code.

When the Value is False

When we set the ShowMyReflectionProperty to False, we simply undo our changes to the visual tree. We remove the containing StackPanel from the original parent. We remove the target element from the StackPanel, swap some layout properties like margin and alignments, and then add the target element back to the original parent element. Real simple.

Summary

So that’s it. You have a class you can now use in any of your WPF apps allowing you to tell any element to display it’s reflection. No need to add additional controls to the project, window or page. You can customize the displayed reflection and since you have the source code, you can expose additional properties as needed to customize it further. Because we’ve correctly modeled the functionality by not trying to contain the target, we also have the added benefit of being able to turn on and off the effect at will. Give it a go by running the sample app and let me know what you think.

Jun 3

Here’s a custom ToolTip style I put together as an example for someone in the MSDN forums:

And here’s the output:

Enjoy!

« Previous Entries