SystemDropShadowChrome

During a training session this week, someone asked about creating a dropshadow.  That reminded me of a useful, but somewhat hidden way of creating decent looking dropshadows in WPF without paying the price of using BitmapEffects. 

As you know, the most straightforward way to add a dropshadow to any content in WPF is to apply the DropShadowBitmapEffect.  That’s a very cool way to do it and it makes a pretty nice dropshadow (and offfers a fair amount of customization).  Unfortunately, though, there are some pretty serious performance tradeoffs to using BitmapEffects and because of that, we almost never use them.

We ran into this perf issue when we were creating the dropshadow for a lot of the system controls.  Most of the popup controls (Menu, ToolTip, ComboBox, etc.) need a dropshadow and (much to my dismay) BitmapEffect just wasn’t cutting it.  That’s where SystemDropShadowChrome enters the story.

We created it to emulate the system drop shadow but in a performant way.  It’s a decorator (like Border) that takes one child.  It basically draws a fuzzy-edged rectangle and then places the content on top it (with an offset).  If your content happens to be a rectangle things look pretty good.  Even if your content is rectangle with rounded corners, you can pull off a pretty good effect.  If your content is, say, an ellipse, well, you’re out of luck.  Here are some examples:

You only get two properties: a Color property (which actually is a Color, not a Brush) that let’s you change the color of the shadow, and a CornerRadius property that you can use to round off the corners on the dropshadow.

The good news is that this thing has pretty good perf.  It’s just a bunch of drawing commands and gradients and all of it gets rendered in code in the OnRender override of the control.

SystemDropShadowChrome is in the Microsoft.Windows.Themes namespace.  We tucked a lot of little gems away in this namespace.  Basically anything that we needed to pull off a visual effect in the system themes, but which didn’t make sense as a first-class element in the platform, got tucked away in there.  Everything is available for your tinkering pleasure.  You’ll have to import the namespace though (and add a reference to one of the theme assemblies).

If you want to experience SystemDropShadowChrome in person, you can download a project here.

11 Comments

Szymon / MAR 26 2007

I’ve came across this classes when I was playing with some default ControlTemplates in Expression Blend. However we started getting runtime error after including reference to one of theme namespaces in XAML. It turned out that we were forcing the application already to run with Windows Areo theme (by merging this dictionary in App.xaml) and later added reference to Windows Classic. I don’t rememeber the correct error now but I wonder if you had similar problems.

Also good thik to now would be how to automatically import the assmebly for current system theme.

Anyway this is excellent post. Thanks for sharing this info and please keep it coming.

Bryan W. / MAY 22 2007

Thanks for posting this little gem on faking a DropShadow.

Andrew Wilkinson / JUL 27 2007

I never really liked the idea of referencing one of the many PresentationFramework.* assemblies, since you never know which one will really be used at runtime. My solution was to write my own ShadowChrome class that would do the required job. I wrote a blog post about it here,

http://andyonwpf.blogspot.com/2006/11/from-shadows.html

Derek / FEB 26 2008

I’m having trouble getting this to work in our application. We have a floating panel to do searches, from which we had to remove the bitmapeffect dropshadow for the usual perf reasons. But using the solution above, the shadow draws on top of another panel, and in general doesn’t behave per the example.

In summary, we have a MainWindow.xaml, which is a container for various other user controls for application content. One of these is a canvas holding a search control. When I put the simpledropshadow around the Canvas, in the same row and column and with the same z-order, I don’t get anything. If I don’t specify the row and column, it draws over the entire left side of MainWindow; if I move the z-order for the shadow lower than the canvas, it doesn’t draw. Any suggestions?

When I run your project and put content inside the borders, it works fine.

Derek / FEB 26 2008

Never mind, I just put the dropshadow in the wrong place. When I put it around a border inside the canvas, it works great. Thanks for this post which solves a small but obvious problem in our application.

Roeland Jimenez / JUN 16 2009

You write: “If your content is, say, an ellipse, well, you’re out of luck.”

This is solved by setting the CornerRadius to 180:

Jerry Nixon / MAR 02 2011

Is there a way to move the position of the shadow to the left side?

Bubba Gump / MAR 25 2011

For circle set CornerRadius to the circle’s radius