Friday, September 24, 2010

Introducing Chrysalis

In this post I am going to introduce the new Chrysalis framework available now from CodePlex at http://chrysalis.codeplex.com. Chrysalis is in an open source framework designed to simplify the development of Silverlight based Windows Phone 7 applications. Whilst it is primarily focused on Model-View-ViewModel (MVVM) related presentation patterns, it can be applied to other designs.

Many times it has been commented that if you are a Silverlight developer (and to some extent a WPF developer), then you now have the skills to write Windows Phone 7 applications. And this is almost true – with the introduction of Windows Phone 7 you can now write Silverlight applications that run on the phone as native apps (with XNA the other option for more graphically rich apps). But at the same time there are a number of new concepts that you will need to consider to write high quality software that runs within the constraints of a mobile device.

Tombstoning

The first consideration that everyone who works with Windows Phone 7 (both in Silverlight and XNA) should be aware of is the interestingly named “tombstoning”. The MSDN documentation has an excellent section on the “Execution Model Overview for Windows Phone” so I will not go into this in detail. In summary, you have to be aware that your application may be exited automatically at any point during its execution (for example when a phone call comes in) – not pushed to the background, but killed outright. At some later point you application may be reactivated, and it is you job as a developer to ensure that all application state is restored. The end user should believe that the app was sat there in the background all the time, even though you know that it was killed and restarted.

The Windows Phone 7 framework will warn you that you application is being deactivated with the PhoneApplicationService.Deactivated event. This is your opportunity to save any state required, either to one of a couple of state bags, or to isolated storage. When the application is restarted then you will receive the PhoneApplicationService.Activated event, and you can restore the UI to its former state.

In reality there is a lot to think about. Firstly you have to ensure that if you are using MVVM then your ViewModels receive the activation and deactivation events. This is complicated by the fact that the PhoneApplicationService.Activated event is often fired before your ViewModel is even created. In addition there is a lot of control state that may need to be maintained – currently focused control, position of scroll bars, etc.

Chrysalis aims to greatly simplify this process.

Choosers

In Windows Phone 7 there are a number of points at which you may need to interact with the built in phone UI, for example to take a photo with the camera, or to retrieve contact information. This is done using “Choosers” (MSDN article).

When you show a chooser we once again experience tombstoning. For the duration of the user interacting with the phone UI, our application is exited, to be restarted later when the interaction has completed. Not only do we now need to restore any state within the application, we must remember that we were calling into a chooser and what we were intending to do with the result – for example if we have multiple sets of contact information on the screen, which were we updating?

Chrysalis aims to allow you to specify a callback within your ViewModel that will receive the result from the chooser. Combined with the tombstoning support, your application should be barely aware that the application was killed and restarted. Instead the chooser will look like any other method call and callback.

Access to Hardware

Although the programming model for Windows Phone 7 is entirely managed code, there are two “flavours” of application – Silverlight and XNA. In several cases features exist within XNA, but not within Silverlight. Whilst these can be accessed by simply adding the XNA assembly references, the APIs sometimes require a different mindset.

Chrysalis aims to provide wrappers where required to make connecting to the hardware available through the XNA framework as simple as using any of the native Silverlight controls.

Summary

To conclude, the Chrysalis framework is now available at http://chrysalis.codeplex.com. While this is only a first release I encourage you to take a look at the basis provided and keep an eye on this blog as I will describe the usage and implementation of new features as they are introduced.

And please provide feedback on existing or new features, either through this blog, or on CodePlex.

Sunday, April 15, 2007

How small can you go? - Part III

In part one of this series of posts ("How small can you go?" 22 Jan 2007) I described how you could design a Windows Presentation Foundation (WPF) control that altered the visibility of specific areas of a UI when then containing window was resized. Compare this to the behaviour of the Office 2007 ribbon, which will hide itself to show more of the edited document when the window is below a certain size. In part II ("How small can you go? - Part II" 15 Feb 2007) I detailed an alternative approach that allowed a trigger to be used when any bindable property (e.g. the width of a window) was below a certain size. In this post I will complete the implementation.


To summarise part II, we implemented an IValueConverter that would return a boolean value indicating whether a specified binding was less than a certain value. This could be used as follows,



<... .Resources>
<cvt:LessThanConverter x:Key="LessThanConverter"/>
</... .Resources>

<DataTrigger Value="True" Binding="{Binding RelativeSource={RelativeSource Self}, Path=ActualWidth, Converter={StaticResource lessThanConverter}, ConverterParameter=200}">
...
</DataTrigger>


While this allowed defining a trigger for when the width was below a specific threshhold, we would have to define the trigger again for the height of the window. What we really need is some way to combine two bindings with a 'logical OR' operation.


Introducing the IMultiValueConverter...


An IMultiValueConverter is similar in principle to an IValueConverter, whereas the latter allows the conversion of a single value into another form (in our case, a double into a bool indicating whether the value is below a threshold), the former will take several values, and combine them into a single output value that is then used as a trigger. We therefore need an IMultiValueConverter that will take a number of booleans and output a single boolean that represents a 'logical OR' of all the input values. We can then use the following XAML,



<... .Resources>
<cvt:LessThanConverter x:Key="lessThanConverter"/>
<cvt:MultiValueOrConverter x:Key="multiValueOrConverter"/>
</... .Resources>

...

<DataTrigger Value="True">
<DataTrigger.Binding>
<MultiBinding Converter="{StaticResource multiValueOrConverter}">
<Binding RelativeSource="{RelativeSource Self}" Path="ActualWidth" Converter="{StaticResource lessThanConverter}" ConverterParameter="200"/>
<Binding RelativeSource="{RelativeSource Self}" Path="ActualHeight" Converter="{StaticResource lessThanConverter}" ConverterParameter="200"/>
</MultiBinding>
</DataTrigger.Binding>
...
</DataTrigger>



This snippet declares two objects, our LessThanConverter from before, and a new MultiValueOrConverter. Following this we have a DataTrigger who's binding is a MultiBinding that takes two bindings that will return true if the width or height is less than 200. By default the MultiBinding will only trigger if all the child bindings are true (a 'logical AND'). We change this behaviour to a 'logical OR' by specifying our multi-value converter. The trigger will now fire if either the element width OR height are less than 200.


The actual code for the multi-value converter is similar in principle to that of a single-value converter. We take an array of input values that we will assume are all boolean values. We then perform a foreach loop over them and if any are true, we return true, otherwise false. Therefore the resulting code is,



using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Data;
using System.Globalization;

namespace SizingApplication2
{
public class MultiValueOrConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
foreach (bool value in values)
{
if (value == true)
return true;
}

return false;
}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}

}
}



If we combine this with the XAML snippet above and include a suitable setter to hide the desired parts of the UI, we now have all the behaviour we require. Advantages of this approach include not requiring any extra elements, and being able to adapt the value converters to any situation where the UI changes based upon a certain value (for example, to display a warning message when a slider is moved above a certain value, or even change its colour as a warning).


The full code for this post and an example usage is available here.

Sunday, March 04, 2007

It's all in the Blend

Recently I've been experimenting with the new software tool Expression Blend. For those of you who do not know, Expression Blend is Microsoft's design tool for XAML and WPF applications and is available as I write in Beta 2 form. It provides a visual design workspace where you can lay out all the elements that make up a UI, and adjust their properties as required.

I have been making extensive use of it to style all the elements in my ribbon UI framework that I am currently developing. For someone who has previously edited the XAML directly it provides a much quicker environment for laying out the UI, with instant feedback on all changes. It also simplifies the introduction of triggers (changes on IsMouseOver, IsPressed, etc.) and animation. As an example, shown below is the application menu button for the ribbon UI. Of course since this is WPF this is all vector based, and smoothly scales up (NB: This screen grab is from an actual live UI - rollover animations, opens a menu when clicked, etc...).


In its current incarnation (beta 2) there are some issues I have had. First of all I have been unable currently to get the whole of my ribbon UI in the designer. To be fair, I haven't really tried fixing this, and it is a large composition of custom controls in a WPF rendered chrome window. It also takes a bit of learning to get used to the way it places elements by default. Of course I never read the help when I started using it which could of helped, and once you understand the basic ideas it is very easy to build up the control structure desired.

My favorite features apart from the ease at which the UI can be styled... One item I'll definitely add here is the gradient eyedropper tool. This is similar to the standard eyedropper, which can pick up individual pixel colours from the screen. However, when the gradient eyedropper tool is dragged across a region of the screen it will automatically pick up entire gradient fills. Great for designing smooth user interfaces. Also I like the simplicity by which you can apply property changes and animation upon events.

Let me know below if anybody else has any experiences of Expression Blend...



Update: After a request for the XAML code I have attached the basic code below (copy and paste into XamlPad to see it). The actual Expression Blend generated XAML is significantly more complex (and much less readable!), and includes all the roll-over behaviour etc.. This is the main reason I chose a designer over hand crafting the XAML. Hopefully the attached code will give you an idea how to approach such designs.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<Page.Resources>
<Style TargetType="{x:Type Button}" x:Key="RibbonApplicationMenuButton">
<Setter Property="Width" Value="37"/>
<Setter Property="Height" Value="37"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>

<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Border BorderThickness="0,0,0,0" CornerRadius="100000,100000,100000,100000" Opacity="1" Margin="0,0,-1,-1" x:Name="ShadowBorder" Background="#39000000"/>
<Border x:Name="OuterBorder" BorderBrush="#FF6E7D95" BorderThickness="1,1,1,1" CornerRadius="100000,100000,100000,100000">
<Border ClipToBounds="False" x:Name="InnerBorder" Width="Auto" Height="Auto" BorderBrush="#FFDDE2EC" BorderThickness="1,1,1,1" CornerRadius="10000,10000,10000,10000">
<Border.Background>
<LinearGradientBrush EndPoint="0.505,0.489" StartPoint="0.512,-0.004">
<GradientStop Color="#FFF3F5F8" Offset="0"/>
<GradientStop Color="#FFC0CADB" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
<Grid Width="Auto" Height="Auto">
<Path RenderTransformOrigin="0.499999990968993,0.0833333333333333" Stretch="Fill" Margin="0,15,0,0" x:Name="path" Width="Auto" Data="F1 M16.5,15.5 C22.163836,15.5 27.559435,15.738094 32.466614,16.168823 L32.5,16.5 C32.5,25.336555 25.336555,32.5 16.5,32.5 7.663444,32.5 0.5,25.336555 0.5000006,16.5 L0.53338605,16.168823 C5.4405661,15.738094 10.836165,15.5 16.5,15.5 z">
<Path.Fill>
<RadialGradientBrush MappingMode="RelativeToBoundingBox" GradientOrigin="0.5,0.5">
<RadialGradientBrush.RelativeTransform>
<TransformGroup>
<ScaleTransform CenterX="0.5" CenterY="0.5" ScaleX="1.077" ScaleY="1.748"/>
<SkewTransform AngleX="0" AngleY="0" CenterX="0.5" CenterY="0.5"/>
<RotateTransform Angle="0" CenterX="0.5" CenterY="0.5"/>
<TranslateTransform X="-0.002" Y="-0.025"/>
</TransformGroup>
</RadialGradientBrush.RelativeTransform>
<GradientStop Color="#FFFFFFFF" Offset="0.375"/>
<GradientStop Color="#FF93A5C2" Offset="1"/>
<GradientStop Color="#FFF2F4F7" Offset="0.529"/>
</RadialGradientBrush>
</Path.Fill>
</Path>
<ContentPresenter HorizontalAlignment="Center" Margin="0,0,0,0" VerticalAlignment="Center" Width="Auto" Height="Auto"/>
</Grid>
</Border>
</Border>
</Grid>

</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>

<Button Style="{StaticResource RibbonApplicationMenuButton}"/>
</Page>

Thursday, February 15, 2007

How small can you go? - Part II

Updated: 19 March 2007 to resolve some errors

In my last post ("How small can you go?" 22 Jan 2007) I presented a custom control that allowed you to determine if the control was below a specific size, and to alter its visual appearance based upon this. There are many cases however where altering appearance based upon size is important (for example, to make the thumb grips on scrollbars disappear when they become too small), and I felt a more generic method of performing this calculation was required.

Ideally this method would not require a special base class as described in my previous post. It should also be as general as possible, allowing bindings to any available dependency properties.

So let us consider how we currently implement triggers,

<Trigger Property="IsMouseOver" Value="True">
...
</Trigger>

<Trigger Property="Width" Value="150">
...
</Trigger>


The first of these examples makes perfect sense. The IsMouseOver property is either true or false. We apply the default style when it is false, and apply any changes specified within the Trigger when it is true. However, the Width property does not have a small number of distinct values. Whilst the above trigger will apply if the width equals 150, it will not if it is 149,148,147,etc. or 151,152,153,etc. If only we had a less-than trigger...


Now let me introduce the IValueConverter interface. This according to the MSDN documentation "Provides a way to apply custom logic to a binding." Basically it allows you to include some logic that alters the value of the property before the trigger performs its comparison.


For example,



<DataTrigger Value="True" Binding="{Binding RelativeSource={RelativeSource Self}, Path=ActualWidth, Converter={StaticResource addTenConverter}, ConverterParameter=150}">
...
</DataTrigger>


Here we specify a custom converter, whose logic simply adds ten to a value. Therefore if the Width of our element is 140, the binding will first call our converter, which will of course return 150. Since this matches the Value attribute, the trigger will be applied. The converter just sits between the Property and the comparison to Value and provides some conversion.


So how does this help us? Well, there is one more attribute we need to introduce. The ConverterParameter attribute allows us to supply an additional parameter to our converter when it does its stuff. Now we can envisage,



<... .Resources>
<cvt:LessThanConverter x:Key="LessThanConverter"/>
</... .Resources>

<DataTrigger Value="True" Binding="{Binding RelativeSource={RelativeSource Self}, Path=ActualWidth, Converter={StaticResource lessThanConverter}, ConverterParameter=200}">
...
</DataTrigger>


Note that we create an instance of the converter as a static resource. The actual code behind the converter is relatively straightforward. All we do is take the supplied value, compare it to the supplied parameter, and return true if the value is less otherwise return false. In fact this is slightly more complex. Whilst a ValueConversionAttribute may be applied to the converter class specifying the type for the parameter, when written in XAML as shown above this is ignored and a string is supplied anyway. Therefore the resulting code is,



using System;
using System.Windows.Data;
using System.Globalization;

[ValueConversion(
typeof(double), typeof(bool), ParameterType = typeof(double))]
public class LessThanConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double doubleValue = (double)value;
double doubleParameter;

if (parameter is double)
doubleParameter
= (double)parameter;
else if (parameter is string)
{
if (!Double.TryParse((string)parameter, out doubleParameter))
throw new FormatException("The parameter for this LessThanConverter could not be converted to a System.Double");
}
else
throw new ArgumentException("The parameter for this LessThanConverer is of an unsupported type", "parameter");

Console.WriteLine(
"{0} < {1}", doubleValue, doubleParameter);

return doubleValue < doubleParameter;
}

public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return new NotSupportedException();
}
}


So now we can trigger when any dependency property that is defined as a double is less than a specified value. The original problem from part 1 however involved changing the appearance of a window when either of the Width or Height properties were below a certain threshold. We can specify two separate triggers, but this requires duplication of all the setters within them. What we really need is some way to apply a 'logical OR' operation to two or more triggers. Next time... The IMultiValueConverter interface.



Technorati tags: , ,

Monday, January 22, 2007

How small can you go?

In the past, creation of fully sizable user interfaces was a tedious job involving writing complex and bugging "pixel-counting" code to layout controls upon a window resize event. Windows Presentation Foundation (WPF) has made the job of creating such UIs much simpler by including a straightforward layout engine within the framework. But sometimes there is a limit to how small you can resize the UI before it becomes unusable.

One solution is the approach used by the 2007 Microsoft Office System, whereby the ribbon control will disappear from view if the window is resized too small, allowing the document content to fill the space. In this post I'll describe how to implement this effect in WPF applications. I will discuss how to implement dependency properties in your custom controls and the strange world of read-only dependency properties.

As a very simple example we will start with a custom control that is styled with a content area, and a toolbar that when sized below a certain size will be hidden (in my WPF ribbon control this is actually a styled Window, however for simplicity here I will use a control).

public class SizingControl : Control
{
}


Now we will add a "dependency property", a special type of property used for WPF applications that allows additional functionality such as data binding, animations and styling. We define these with the DependencyProperty.Register static method, supplying a property name, property type and owner type. In addition, metadata may be added defining addition information such as default values. In addition we add a standard CLR property of the same name, passing the value to and from the property system with the DependencyObject.GetValue and DependencyObject.SetValue methods. In this case we add a dependency property to specify the size below which the control will display a different UI.



public static readonly DependencyProperty SmallSizeProperty = DependencyProperty.Register("SmallSize", typeof(Size), typeof(SizingControl), new UIPropertyMetadata(new Size(0.0, 0.0)));

public Size SmallSize
{
get
{
return (Size)GetValue(SmallSizeProperty);
}
set
{
SetValue(SmallSizeProperty, value);
}
}


Next we add a read-only dependency property that indicates whether the control is below the specified size. The Windows SDK warns against using read-only dependency properties in many cases, and suggests that such properties should only be used "for state determination". Think of this as properties of the form "IsXXX" (such as IsMouseOver).


To register a read-only dependency property, we use the DependencyProperty.Register.ReadOnly static method, which rather than a DependencyProperty, returns a DependencyPropertyKey. To set the value we can use this with the respective override of DependencyObject.SetValue, however no suitable override of DependencyObject.GetValue exists. In fact, the property system does not allow us to get a value of a dependency property that is marked as read-only. So how do we obtain this value? The answer is that we have to include a private field to contain the property value. Since by its very nature a read-only property may only be set by the owner class, we can always ensure that the value in the field is synchronized with that of the dependency property. To avoid writing code that breaks this rule, I tend to encapsulate this logic into a private property setter (note that property setters and getters with different accessibility is a feature of C# 2.0).



private bool isSmall;

public static readonly DependencyPropertyKey IsSmallPropertyKey = DependencyProperty.RegisterReadOnly("IsSmall", typeof(bool), typeof(SizingControl), new UIPropertyMetadata(false));

public bool IsSmall
{
get
{
return isSmall;
}
private set
{
if (value != isSmall)
{
isSmall
= value;
SetValue(IsSmallPropertyKey, value);
}
}
}


Now all is required is to override the OnRenderSizeChanged event of our control, and determine whether the control is small or not.



private void UpdateIsSmall(Size newSize)
{
IsSmall
= (newSize.Width < SmallSize.Width || newSize.Height < SmallSize.Height);
}

protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
// Calculate whether the window size is smaller than the specified values
UpdateIsSmall(sizeInfo.NewSize);

// Call the base method
base.OnRenderSizeChanged(sizeInfo);
}


The XAML below shows how to use the control to hide a toolbar when the window is too small. We style the control with the desired content, and set a trigger on the IsSmall property to show or hide the toolbar as required.



<Window x:Class="SizingApplication.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="SizingApplication" Height="300" Width="300" xmlns:local="clr-namespace:SizingApplication" Background="Silver">
<Window.Resources>
<Style x:Key="MySizingRegion" TargetType="local:SizingControl">
<Setter Property="SmallSize" Value="200,200"/>

<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:SizingControl">
<DockPanel>
<ToolBar x:Name="toolBar" DockPanel.Dock="Top" Height="50">
<Label VerticalAlignment="Center">My ToolBar</Label>
</ToolBar>
<Border Margin="10" Background="White"/>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsSmall" Value="True">
<Setter TargetName="toolBar" Property="Visibility" Value="Collapsed"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>

<Grid>
<local:SizingControl Style="{StaticResource MySizingRegion}"/>
</Grid>
</Window>


The full code for this post is here.

Friday, November 24, 2006

Ribbon controls are legal!

Here is the news that Microsoft have launched a licensing program for those who wish to clone the Office 2007 UI (from Jensen Harris' blog). This is a royalty-free scheme whereby anyone wishing to use part of the Office 2007 user interface (e.g. the ribbon) can recreate it in their applications (note that this offering does not provide any code).

There are some restrictions applied however, in particular that the interface must adhere to the supplied UI guidelines. These are very detailed so places quite a burden on the programmer implementing the controls; however this should at least ensure that the end user can confidently use a ribbon-enabled application with the existing knowledge of how the UI should work. Microsoft have done a great job in explaining the requirements - for example they describe exactly how the ribbon should resize - so I'm looking forward to having an accurate check-list of requirements to implement in my controls.

For more information check out the links in Jensen' blog post...

Sunday, November 05, 2006

From the shadows

When styling controls that have a Popup element (e.g. menus, combo boxes, etc.) a common visual cue is a drop-shadow below the pop-up. WPF contains a DropShadowBitmapEffect that will do this all for us, hence,

<Border ...>
<Border.BitmapEffect>
<DropShadowBitmapEffect Softness=".5" ShadowDepth="5" Color="Black"/>
</Border.BitmapEffect>
</Border>


The result is shown on the left below. However, the DropShadowBitmapEffect is a bit overkill for our needs. It is designed to add drop-shadows to arbitrary shapes (for example the text below) whereas a pop-up is generally rectangular.


If you inspect the default WPF styles you will find that a drop shadow is applied via a Decorator called Microsoft.Windows.Themes.SystemDropShadowChrome. This however is hidden away in PresentationFramework.Luna.dll and designed for use by the default styles.

For my controls I have developed my own decorator to do a similar job. Firstly I have decided to make some assumptions to improve performance - namely that the drop-shadow colour is always black, and that it is always to the bottom-right. All that is required then is to implement a custom "Decorator". Decorators are controls that add some additional rendering to a single element (of course that element may be a Panel that contains several other elements). We can then draw a drop-shadow in the OnRender method consisting of a set of linear and radial gradients to mimic the shadow.

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows

class ShadowChrome : Decorator
{
// *** Fields ***

private static SolidColorBrush backgroundBrush;
private static LinearGradientBrush rightBrush;
private static LinearGradientBrush bottomBrush;
private static RadialGradientBrush bottomRightBrush;
private static RadialGradientBrush topRightBrush;
private static RadialGradientBrush bottomLeftBrush;

// *** Constructors ***

static ShadowChrome()
{
MarginProperty.OverrideMetadata(typeof(ShadowChrome), new FrameworkPropertyMetadata(new Thickness(0, 0, 4, 4)));

CreateBrushes();
}

// *** Overriden base methods ***

protected override void OnRender(DrawingContext drawingContext)
{
// Calculate the size of the shadow

double shadowSize = Math.Min(Margin.Right, Margin.Bottom);

// If there is no shadow, or it is bigger than the size of the child, then just return

if (shadowSize <= 0 || this.ActualWidth < shadowSize*2 || this.ActualHeight < shadowSize * 2)
return;

// Draw the background (this may show through rounded corners of the child object)

Rect backgroundRect = new Rect(shadowSize, shadowSize, this.ActualWidth - shadowSize, this.ActualHeight - shadowSize);
drawingContext.DrawRectangle(backgroundBrush, null, backgroundRect);

// Now draw the shadow gradients

Rect topRightRect = new Rect(this.ActualWidth, shadowSize, shadowSize, shadowSize);
drawingContext.DrawRectangle(topRightBrush, null, topRightRect);

Rect rightRect = new Rect(this.ActualWidth, shadowSize * 2, shadowSize, this.ActualHeight - shadowSize * 2);
drawingContext.DrawRectangle(rightBrush, null, rightRect);

Rect bottomRightRect = new Rect(this.ActualWidth, this.ActualHeight, shadowSize, shadowSize);
drawingContext.DrawRectangle(bottomRightBrush, null, bottomRightRect);

Rect bottomRect = new Rect(shadowSize * 2, this.ActualHeight, this.ActualWidth - shadowSize * 2, shadowSize);
drawingContext.DrawRectangle(bottomBrush, null, bottomRect);

Rect bottomLeftRect = new Rect(shadowSize, this.ActualHeight, shadowSize, shadowSize);
drawingContext.DrawRectangle(bottomLeftBrush, null, bottomLeftRect);
}

// *** Private static methods ***

private static void CreateBrushes()
{
// Get the colors for the shadow

Color shadowColor = Color.FromArgb(128, 0, 0, 0);
Color transparentColor = Color.FromArgb(16, 0, 0, 0);

// Create a GradientStopCollection from these

GradientStopCollection gradient = new GradientStopCollection(2);
gradient.Add(new GradientStop(shadowColor, 0.5));
gradient.Add(new GradientStop(transparentColor, 1.0));

// Create the background brush

backgroundBrush = new SolidColorBrush(shadowColor);

// Create the LinearGradientBrushes

rightBrush = new LinearGradientBrush(gradient, new Point(0.0, 0.0), new Point(1.0, 0.0));
bottomBrush = new LinearGradientBrush(gradient, new Point(0.0, 0.0), new Point(0.0, 1.0));

// Create the RadialGradientBrushes

bottomRightBrush = new RadialGradientBrush(gradient);
bottomRightBrush.GradientOrigin = new Point(0.0, 0.0);
bottomRightBrush.Center = new Point(0.0, 0.0);
bottomRightBrush.RadiusX = 1.0;
bottomRightBrush.RadiusY = 1.0;

topRightBrush = new RadialGradientBrush(gradient);
topRightBrush.GradientOrigin = new Point(0.0, 1.0);
topRightBrush.Center = new Point(0.0, 1.0);
topRightBrush.RadiusX = 1.0;
topRightBrush.RadiusY = 1.0;

bottomLeftBrush = new RadialGradientBrush(gradient);
bottomLeftBrush.GradientOrigin = new Point(1.0, 0.0);
bottomLeftBrush.Center = new Point(1.0, 0.0);
bottomLeftBrush.RadiusX = 1.0;
bottomLeftBrush.RadiusY = 1.0;
}
}



This may then be used as shown in the following XAML. Note that the Margin property is used for two uses. Firstly it provides an area around the element to render the drop-shadow (this is important in a Popup since it ensures the drop-shadow is within the pop-up window), and also specifies to ShadowChrome the size to render the drop-shadow.

<ShadowChrome>
<Border Margin="0,0,5,5" .../>
</ShadowChrome>