Know your place in life [Free PlaceImage control makes it easy to add placeholder images to any WPF, Silverlight, or Windows Phone application!]
One of the challenges with referencing online content is that you never know just how long it will take to download... On a good day, images show up immediately and your application has exactly the experience you want. On a bad day, images take a looong time to load - or never load at all! - and your application's interface is full of blank spaces. Applications that make use of remote images need to be prepared for variability like this and should have "placeholder" content to display when the desired image isn't available.
Of course, there are a variety of ways to deal with this; I thought it would be neat to create a reusable, self-contained class and share it here. I envisioned a simple control that "looked" like a standard Image element (i.e., had the same API), but that seamlessly handled the work of displaying placeholder content before an image loaded and getting rid of it afterward. Naturally, I also wanted code that would run on WPF, Silverlight, and Windows Phone!
<delay:PlaceImage PlaceholderSource="PlaceholderPhoto.png" Source="{Binding ImageUri}"/>
The result of this exercise is something I've called PlaceImage. PlaceImage has the same API as the framework's Image and can be dropped in pretty much anywhere an Image is used. To enable the "placeholder" effect, simply set the PlaceholderSource property to a suitable image. (Aside: While you could specify another remote image for the placeholder, the most sensible thing to do is to reference an image that's bundled with the application (e.g., as content or a resource).) PlaceImage immediately shows your placeholder image and waits for the desired image to load - at which point, PlaceImage swaps it in and gets rid of the placeholder!
I've written a sample application for each of the supported platforms that displays contact cards of imaginary employees. When the sample first runs, none of the remote images have loaded, so each card shows the "?" placeholder image:
After a while, some of the remote images will have loaded:
Eventually, all the remote images load:
Thanks to placekitten for the handy placeholder images!
Making use of online content in an application is easy to do and a great way to enrich an application. However, the unpredictable nature of the network means content might not always be available when it's needed. PlaceImage makes it easy to add placeholder images to common scenarios and helps keep the user interface free of blank spaces. With easy support for WPF, Silverlight, and Windows Phone, you can add it to pretty much any XAML-based application!
Notes:
-
Just like
Image,PlaceImagehas properties for Source, Stretch, and StretchDirection (the last being available only on WPF).PlaceImage's additionalPlaceholderSourceproperty is used just likeSourceand identifies the placeholder image to be displayed before theSourceimage is available. (So set it to a local image!) -
Changes to the
Sourceproperty of a loadedImageimmediately clear its contents. Similarly, changing theSourceof a loadedPlaceImageimmediately switches to its placeholder image while the new remote content loads. You can trigger this behavior in the sample application by clicking any kitten. -
Because the Silverlight version of the demo application references web content, it needs to be run from the
PlaceImageDemoSL.Webproject. (Although runningPlaceImageDemoSLwill show placeholders, the kitten pictures never load.) The MSDN article URL Access Restrictions in Silverlight has more information on Silverlight's "cross-scheme access" limitations. -
Control subclasses typically live in a dedicated assembly and define their default Style/Template in
Generic.xaml. This is a great, general-purpose model, but I wantedPlaceImageto be easy to add to existing projects in source code form, so it does everything in a single file. All you need to do is includePlaceImage.csin your project, andPlaceImagewill be available in theDelaynamespace. -
The absence of the
StretchDirectionproperty on Silverlight and Windows Phone isn't the only platform differencePlaceImageruns into: whereas Silverlight and Windows Phone offer the handy Image.ImageOpened event, WPF has only the (more cumbersome) BitmapSource.DownloadCompleted event. The meaning of these two events isn't quite identical, but for the purposes ofPlaceImage, they're considered equivalent.