Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Creating a dynamic drop shadow

0.00/5 (No votes)
24 May 2012 1  
How to create and style a container control that can be used to create completely ridiculous drop shadows on any contained control.

DynamicDropshadow test application

Introduction

This article illustrates how to create and style a container control that can be used to create completely ridiculous drop shadows on any contained control. It also shows the principles of how to create a custom WPF control. The shadows might just bring that extra bit of attention to your application or perhaps ruin it - if used on all controls.

Background

I saw a jQuery example displaying dynamic drop shadows and thought it would look much better in WPF. Therefore I decided to try it out...

The Solution

I have created a single project containing the custom WPF container control. The class MainWindow holds a DependencyProperty MousePosition. All of the container controls bind to this property for updates on the mouse position.

The class diagram:

The class diagram


Using the DynamicDropshadow control:

<Window x:Class="Dk.Nmt.Development.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:my="clr-namespace:Dk.Nmt.Development"
    Title="MainWindow" Height="449" Width="567">
  <Grid>
    <my:DynamicDropshadow Height="131" HorizontalAlignment="Left" Margin="325,63,0,0" 
        x:Name="dynamicDropshadow1" VerticalAlignment="Top" Width="178" 
        MousePosition="{Binding Path=MousePosition, RelativeSource={RelativeSource AncestorType=Window}}">
      <Label>Wrapped control goes here...</Label>
    </my:DynamicDropshadow>
...

The style of the DynamicDropshadow implements a control template that uses a border to place the drop shadow on:

<Style x:Key="DynamicDropshadowStyle" TargetType="{x:Type Development:DynamicDropshadow}">
    <Setter Property="OverridesDefaultStyle" Value="True" />
    <Setter Property="Foreground" Value="White" />
    <Setter Property="FontFamily" Value="Tahoma" />
    <Setter Property="FontSize" Value="11px" />
    <Setter Property="Padding" Value="6" />
    <Setter Property="Background" Value="Transparent"/>
    <Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type Development:DynamicDropshadow}">
            <Border x:Name="PART_DropShadowBorder" CornerRadius="5" 
                Background="{TemplateBinding Background}">
                <Border.Effect>
                    <DropShadowEffect 
                        Color="{Binding ShadowColor, RelativeSource={RelativeSource TemplatedParent}}" 
                        Opacity="{Binding ShadowOpacity, RelativeSource={RelativeSource TemplatedParent}}"
                        Direction="{Binding Direction, RelativeSource={RelativeSource TemplatedParent}}" 
                        ShadowDepth="{Binding ShadowDepth, RelativeSource={RelativeSource TemplatedParent}}"
                        BlurRadius="{Binding ShadowBlur, RelativeSource={RelativeSource TemplatedParent}}"/> 
                </Border.Effect>
                <ContentPresenter x:Name="PART_DropShadowContent" 
                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
            </Border>
        </ControlTemplate>
    </Setter.Value>
    </Setter>
</Style>

Calculating the dropshadow is done when the mouse is moved. The calculation is done on the basis of the direction and distance to the mouse pointer:

public void CalcDropShadow()
{
    // Get the position to the mouse, relative to the center of the control
    var p = Mouse.GetPosition(this); 
    p.Offset(-Width / 2, -Height / 2);
    // Calculate the angle to the mouse position
    if (p.X > 0 && p.Y < 0)
    Direction = Math.Atan(-p.Y / p.X) * (180f / Math.PI) - 180;
    if (p.X < 0)
    Direction = Math.Atan(-p.Y / p.X) * (180f / Math.PI);
    if (p.X > 0 && p.Y > 0)
    Direction = Math.Atan(-p.Y/p.X)*(180f/Math.PI) + 180;
    // Calculate distance, depth and blur
    double distance = Math.Sqrt(Math.Pow(p.X, 2) + Math.Pow(p.Y, 2));
    ShadowDepth = 1 + .1 * distance;
    ShadowBlur = Math.Max(20 - .1 * distance,5); 
}

I chose to let the shadow become deeper and less blurry with the distance to the mouse.

Points of Interest

Some controls like Calendar apparently lose ClearType when effects are applied to them.

History

This is version 1.0.0.0.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here