4

When I add a dropshadow bitmap effect to a rectangle, the dropshadow takes into account the transparency of the rectangle (makes sense). Is there a way to render a dropshadow on a transparent rectangle 'as if' the rectangle were opaque? ie what would appear is a rectangle-shaped 'hole', with a dropshadow.

Here is the XAML for a transparent rectangle with a dropshadow - nothing is displayed:

<Rectangle Fill="Transparent" Margin="10" Width="100" Height="100">
  <Rectangle.BitmapEffect>
    <DropShadowBitmapEffect/>
  </Rectangle.BitmapEffect>
</Rectangle>
mackenir
  • 10,801
  • 16
  • 68
  • 100

4 Answers4

5

Drop this into Kaxaml. It creates a transparent Rectangle of size 500x500, with a SystemDropShadowChrome Decorator. The drop shadow's clip is set to exclude the Rectangle's region.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:theme="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Aero"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Canvas>
        <theme:SystemDropShadowChrome Margin="0,0,5,5">
            <Rectangle Width="500" Height="500" Fill="transparent"/>
            <theme:SystemDropShadowChrome.Clip>
                <CombinedGeometry GeometryCombineMode="Exclude">
                    <CombinedGeometry.Geometry1>
                        <RectangleGeometry Rect="0,0,505,505"/>
                    </CombinedGeometry.Geometry1>
                    <CombinedGeometry.Geometry2>
                        <RectangleGeometry Rect="0,0,500,500"/>
                    </CombinedGeometry.Geometry2>
                </CombinedGeometry>
            </theme:SystemDropShadowChrome.Clip>
        </theme:SystemDropShadowChrome>
    </Canvas>
</Page>

If you want your drop shadow to have rounded corners, then set the CornerRadius of the SystemDropShadowChrome to whatever (let's say 10), then Geometry1's Left and Top values to 10, then the RadiusX and RadiusY of each RectangleGeometry to 10.

moswald
  • 11,491
  • 7
  • 52
  • 78
  • It works! Although it doesn't seem like you need that transparent Rectangle (or any object) enclosed in the shadow. My only problem is can this work for dynamically resized content? – Domokun Oct 14 '11 at 04:38
1

I'd love to see better solution, but here is what I usually do (beware: creepy code ahead).

Wrap rectangle to three-four rectangles, and play with stroke color, making it darker and darker as it goes to original rectangle. Here is the code:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   <Grid>
      <Rectangle
         Width="106"
         Height="106"
         Stroke="#10000000"
         StrokeThickness="1"/>
      <Rectangle
         Width="104"
         Height="104"
         Stroke="#5C000000"
         StrokeThickness="1"/>
      <Rectangle
         Width="102"
         Height="102"
         Stroke="#AC000000"
         StrokeThickness="1"/>
      <Rectangle
         Width="100"
         Height="100"
         Fill="Transparent"
         Stroke="#FF000000"
         StrokeThickness="1">
      </Rectangle>
   </Grid>
</Page>

This gives you:

alt text http://img521.imageshack.us/img521/7664/shadowo.jpg

Another approach would be with borders - it's better because you don't have to specify dimensions, when you put them inside Grid.

And the best approach (never seen implemented though): custom pixel shader, which makes what you want.

Anvaka
  • 15,658
  • 2
  • 47
  • 56
  • There is another hack that I implemented once to create a 'blurred rectangle' without using BitmapEffects: create a 3x3 grid, with rectangles in each 'edge' cell filled using a gradient. The corner cells were filled with radial gradients. Other cells with linear gradients. A bit of a palaver, but it was to avoid nasty aliasing effects when animating something with a drop-shadow applied to it. – mackenir Feb 19 '10 at 12:26
  • Maybe the 'solution' is to create a Clip path that exposes the shadowed areas, and clips out the rectangle itself... – mackenir Feb 19 '10 at 12:27
1

Well, here is one long-winded way to implement a rectangular 'drop-shadow' without using a bitmap effect. In this case the centre of the 'shadow rectangle' is coloured in, but it could be set to transparent to give you a 'halo' style drop shadow (i.e., equal all the way round - not offset)

<UserControl x:Class="RectShadow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:System="clr-namespace:System;assembly=mscorlib">
    <UserControl.Resources>
        <System:Double x:Key="CornerSize">5</System:Double>
        <Color x:Key="ShadowColor">#60000000</Color>
        <Color x:Key="TransparentColor">#00000000</Color>
    </UserControl.Resources>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>   
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="auto"/>
            <ColumnDefinition/>
            <ColumnDefinition Width="auto"/>
        </Grid.ColumnDefinitions>

        <Rectangle Width="{StaticResource CornerSize}" Height="{StaticResource CornerSize}">
            <Rectangle.Fill>
                <RadialGradientBrush Center="1,1" GradientOrigin="1,1" RadiusX="1" RadiusY="1">
                    <GradientStop Color="{StaticResource ShadowColor}"/>
                    <GradientStop Offset="1" Color="{StaticResource TransparentColor}"/>
                </RadialGradientBrush>
            </Rectangle.Fill>
        </Rectangle>

        <Rectangle Grid.Row="2" Grid.Column="2" Width="{StaticResource CornerSize}" Height="{StaticResource CornerSize}">
            <Rectangle.Fill>
                <RadialGradientBrush Center="0,0" GradientOrigin="0,0" RadiusX="1" RadiusY="1">
                    <GradientStop Color="{StaticResource ShadowColor}"/>
                    <GradientStop Offset="1" Color="{StaticResource TransparentColor}"/>
                </RadialGradientBrush>
            </Rectangle.Fill>
        </Rectangle>

        <Rectangle Grid.Row="0" Grid.Column="2" Width="{StaticResource CornerSize}" Height="{StaticResource CornerSize}">
            <Rectangle.Fill>
                <RadialGradientBrush Center="0,1" GradientOrigin="0,1" RadiusX="1" RadiusY="1">
                    <GradientStop Color="{StaticResource ShadowColor}"/>
                    <GradientStop Offset="1" Color="{StaticResource TransparentColor}"/>
                </RadialGradientBrush>
            </Rectangle.Fill>
        </Rectangle>

        <Rectangle Grid.Row="2" Grid.Column="0" Width="{StaticResource CornerSize}" Height="{StaticResource CornerSize}">
            <Rectangle.Fill>
                <RadialGradientBrush Center="1,0" GradientOrigin="1,0" RadiusX="1" RadiusY="1">
                    <GradientStop Color="{StaticResource ShadowColor}"/>
                    <GradientStop Offset="1" Color="{StaticResource TransparentColor}"/>
                </RadialGradientBrush>
            </Rectangle.Fill>
        </Rectangle>

        <Rectangle Grid.Column="1">
            <Rectangle.Fill>
                <LinearGradientBrush EndPoint="0,1">
                    <GradientStop Offset="1" Color="{StaticResource ShadowColor}"/>
                    <GradientStop Color="{StaticResource TransparentColor}"/>
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>


        <Rectangle Grid.Column="1" Grid.Row="2">
            <Rectangle.Fill>
                <LinearGradientBrush EndPoint="0,1">
                    <GradientStop Color="{StaticResource ShadowColor}"/>
                    <GradientStop Offset="1" Color="{StaticResource TransparentColor}"/>
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>

        <Rectangle Grid.Row="1">
            <Rectangle.Fill>
                <LinearGradientBrush EndPoint="1,0">
                    <GradientStop Offset="1" Color="{StaticResource ShadowColor}"/>
                    <GradientStop Color="{StaticResource TransparentColor}"/>
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>

        <Rectangle Grid.Row="1" Grid.Column="2">
            <Rectangle.Fill>
                <LinearGradientBrush EndPoint="1,0">
                    <GradientStop Color="{StaticResource ShadowColor}"/>
                    <GradientStop Offset="1" Color="{StaticResource TransparentColor}"/>
                </LinearGradientBrush>
            </Rectangle.Fill>
        </Rectangle>

        <Rectangle Grid.Row="1" Grid.Column="1">
            <Rectangle.Fill>
                <SolidColorBrush Color="{StaticResource ShadowColor}"/>
            </Rectangle.Fill>
        </Rectangle>
    </Grid>
</UserControl>
mackenir
  • 10,801
  • 16
  • 68
  • 100
-2

wrap the rectangle in a border. and add a shadow to the border. you'll get the same effect.

holden321
  • 1,166
  • 2
  • 17
  • 32