9 March 2009
While adding Gravatar support to my blog comments yesterday, I realized that it is a nice candidate for a simple control or a Uri-to-image value converter for Silverlight, and also WPF.
In fact, any application with a user’s e-mail address, or a contact list, could benefit greatly by this functionality. It’s a sweet addition that just works and provides a rich experience in just a few minutes.
Since only a hash is used of the e-mail, it is secure enough to work from any app, simply using a URL, and without having to worry about messy web services, authentication, or security issues. Even better, with Silverlight’s reliance on the web browser’s network stack, you get caching and other nice functionality for free.
I decided to quickly implement this as an actual custom control, so that I could take advantage of data binding with the Email field, and demonstrate some simple code sharing concepts. This could have easily been done with a few lines of code behind and an Image instead.
It is then super easy to add a Gravatar control within a data template anywhere that your business object has an e-mail (or other unique identifying field). Gravatar even supports Identicons (enabled by default in my control implementation), that assign a pretty unique geometric image to the e-mail in the case that the user hasn’t setup their gravatar yet.
This means that you can add images of users without messy database image work, personalizing their e-mail contact list, and otherwise making things look nice, for very little cost. Add it to
So, to use the control, just make sure to define an xmlns attribute for the control assembly, then just set the Email dependency property value. A few other properties are also available, and you should set the Height and Width to typically a square. Ratings and a default image Uri are also supported through other properties. When setting the Email property in Expression Blend or even Visual Studio at design time, you’ll even get the image in there.
Here’s implementation details on the URL format that Gravatar uses, and is implemented by this control.
When using the control in code behind or XAML, you’ll find it 100% compatible between WPF and Silverlight. Easy. What’s next? Here’s how it was done…
There are a few steps I took throughout the process to make the control WPF-compatible enough that I could cross-compile the same source code and XAML template. Here are the steps I took.
To create an application or control that works in WPF and Silverlight, you need to use the following XML namespace declaration:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" />
This is one of those simple steps that I can’t stress enough!
The Silverlight project serves as the “master” control, and the WPF project uses file links to reference the source files from the Silverlight project. This enables easy reuse, since making a change in one project immediately affects the next build of the other project type.
Since the Silverlight subset provides a good migration path, you typically will want to:
For custom controls, the default style information that hooks up Generic.xaml’s default control template and style is set using default style keys. WPF uses a one-time static constructor for this, while Silverlight uses a per-instance DefaultStyleKey setter.
This is easiest accomplished using pre-processor directives from C# for the SILVERLIGHT name that is defined by the Silverlight project types and build tools.
#if !SILVERLIGHT /// <summary> /// Static initializer for the Gravatar type. /// </summary> static Gravatar() { DefaultStyleKeyProperty.OverrideMetadata(typeof(Gravatar), new FrameworkPropertyMetadata(typeof(Gravatar))); } #endif /// <summary> /// Initializes a new instance of the Gravatar control. /// </summary> public Gravatar() { #if SILVERLIGHT DefaultStyleKey = typeof(Gravatar); #endif Loaded += (o, e) => ApplyTemplate(); }
MD5 isn’t pretty, but it is simple and used across the web. I used David Anson’s implementation of MD5 for Silverlight. For the WPF version, the standard MD5 code in System.Security.Cryptography is used.
Even though you can link in the Generic.xaml file that is 100% WPF source compatible, at build time, the resource won’t make its way properly into the metadata as “Themes\Generic.xaml”. To work around this, you’ll see in the WPF project that the linked Generic.xaml is in the root of the library, and contains the actual style information. WPF’s merged dictionary resource feature is then used inside a Themes\Generic.xaml file to pull in the linked Xaml content:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="/Controls.Gravatar;component/generic.xaml"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary>
Do note the assembly name in there. Hacky, but functional.
If the image fails to load, the control falls back to use an embedded resource stream. This took some hacky code, which you’ll find in the source download. Effectively, on WPF, I needed to use a Jpeg bitmap image decoder, vs. Silverlight that has a simple centralized decoder that is not codec-specific.
I used simple #if SILVERLIGHT / #else / #endif preprocessor constructs to factor out the code differences.
Silverlight’s built in HttpUtility class is used for URL encoding as needed. This is the utility class found in the System.Windows.Browser namespace and assembly, and included with the runtime.
In WPF’s case, System.Web (ASP.NET)’s HttpUtility is used for the same exact functionality. There are opportunities for developers not looking to use a fallback URL image to factor this dependency and startup time peformance hit, I’m sure.
If you are working with a simple Silverlight application project and not through a web server or web project, you’ll likely see that the URL scheme at runtime is file://. This means that the images cannot be loaded cross-scheme, so this is perfectly normal operation:
As long as your final application will be hosted on a web server or corporate network server that uses the http:// scheme, your application should be fine.
The download contains simple samples, source projects for WPF and Silverlight, and release binaries. This code is licensed under the Microsoft Public License (Ms-PL).
Hope this helps!
Jeff Wilcox is a Software Engineer at Microsoft in the Open Source Programs Office (OSPO), helping Microsoft engineers use, contribute to and release open source at scale.