Windows Phone 7 allows us to create the UI for an application in Silverlight. (Or in XNA but just now I'm focusing on Silverlight.) Silverlight is known for it's excellent visual capabilities and ability to easily create great graphical effects. Let's look at what's available to us in Windows Phone 7.
Windows Phone 7 supports 3 effects: BlurEffect, ShaderEffect and DropShadowEffect. Silverlight (on the PC/Web) also specifies a PixelShader but this is not supported on the phone.
Effects can be applied to any UIElement but lets see how the BlurEffect and DropShadowEffect can be applied to a TextBlock. (A ShaderEffect is a bit more complicated and there's an example in MSDN.)
Here's a TextBlock you may recognise from a new "Windows Phone Application"
<TextBlock Text="page title" x:Name="textBlockListTitle" Style="{StaticResource PhoneTextPageTitle2Style}" />
And it (in the designer and emulator) looks like this:
Adding a BlurEffect is as easy as this:
<TextBlock Text="page title" x:Name="textBlockListTitle" Style="{StaticResource PhoneTextPageTitle2Style}"> <TextBlock.Effect> <BlurEffect Radius="10" /> <TextBlock.Effect>
<TextBlock>
which creates the following effect:
Or we can add a DropShadowEffect thusly:
<TextBlock Text="page title" x:Name="textBlockListTitle" Style="{StaticResource PhoneTextPageTitle2Style}"> <TextBlock.Effect> <DropShadowEffect BlurRadius="15" Color="Azure" Direction="325" ShadowDepth="10" /> <TextBlock.Effect> <TextBlock>
to create:
Both those effect images are from the designer. But if we look at them in the emulator we see this:
The effect isn't applied.
Don't be fooled. This isn't an error or limitation of the emulator. This is what gets rendered on the phone with the above code.
Fear not though. It's a simple fix. Simply set the CacheMode on the UIElement that the effect is being applied to to "BitmapCache".
Like this:
<TextBlock CacheMode="BitmapCache"
Then in the emulator we see:
and
So why does this work?
I haven't been able to find out the official reason, but here's my educated guess. If I find out the official reason I'll update this.
Silverlight (on the web/PC) always runs in the UI thread (unless you create any others yourself obviously). On the Phone it's different. The phone has two "main" threads. The UI thread and the "Render" thread which is used by the GPU. (Non-phone Silverlight may not always have access to a GPU while the phone always has one.)
Because the phone runs in a constrained environment it's important for it to be small. It therefore doesn't make sense for things to be specified twice when they could only exist once. I suspect that the ability to generate the effects is one such thing.
As a visual effect it makes sense for it to be calculated/generated/processed by the GPU so having the ability to also produce the effect by the process generating the visuals on the UI thread (the CPU) would just be unnecessary duplication.
Setting the CacheMode to BitmapCache forces the UIElement to be rendered by the GPU (as only it can handle Bitmap caching).
Of course it would be nice if the framework could also realise that these effects can only be applied by the GPU and so automatically use it to render them. Maybe this will be addressed in the future. Until then, at least we now know the work around.
What about the display in the designer?
Well that's WPF running on the desktop and handles the applying of effects without the need to force their rendering by a special process(or).