If you have been working at all with Vista. You have notice a nice shadow effect around all of the windows. It isn't a drop shadow, more of a fuzzy fade all around the window. This does an excellent job of layering the windows for the user and all around nice effect. Now in Windows Presentation Foundation this is referred to as a halo effect or outer glow and can be done with a bitmap effect. Silverlight does not have the equivalent of this. To create this in Silverlight you need to roll your own version. I have created a user control that you can use to generate this effect.
First off, the way I would like to do this is to extend the border class, creating my own custom border that has extended properties to render the halo. However the border (and rectangle for that matter) are both sealed classes so we have to go another route. The most straight forward approach to me was to create a user control and go with the layered approach rather than the container route.
Here is an example with the halo:
And without the halo:
The XAML to define the user control shown above. This is the XAML for the container control and shadow only.
<AmazonAG:BorderShadow x:Name="SearchShadow" Height="195" Width="330" Canvas.Left="0" Canvas.Top="0" Fill="#FFFFFFFF" Stroke="#FFCC4E06" StrokeThickness="1" FillOpacity="0.8" CornerRadius="5" ShadowWidth="7" />
In its simplest terms this is a rectangle defined by the Width, Height, Fill, Stroke, StrokeThickness, FillOpacity and CornerRadius properties. The rectangle is generated based on these properties and the shadow is added dynamically around it. The rectangle properties are the same as those for a standard rectangle, so the Fill, Stroke properties can be used to apply gradient brushes as well.
The ShadowWidth property is used to determine the thickness of the shadow itself. In a slight twist, I didn't like a linear gradient for the shadow. The effect just didn't look good to me, so I used a sine calculation for the curve of the alpha in the shadow. I think this creates a much better fade effect on the background. You can review this code in the SinAlpha method below.
A nice addition would be to add the ability to determine the darkness of the halo and possibly the color of the halo. Currently the halo effect is gray scale beginning at 48 calculating a sine wave to 0 opacity. I have included all of the code for the user control. Have fun, let me know what you think.
Here is the XAML for the user control:
<UserControl x:Class="AmazonAG.BorderShadow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Loaded="UserControl_Loaded" SizeChanged="UserControl_SizeChanged"
>
<Canvas x:Name="LayoutRoot" />
</UserControl>
As you can see the XAML is just a place holder for my control, all of the heavy lifting to generate the halo is in the code behind.
Here is the code behind the user control:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace AmazonAG
{
public partial class BorderShadow : UserControl
{
#region Variables
// list of border controls used to generate the halo effect
private List<Border> _borderShadows = new List<Border>();
// base rectangle control - the halo surrounds this control
private Rectangle _rectangleFill = new Rectangle();
#endregion
#region Properties
private int _shadowWidth = 7;
public int ShadowWidth
{
get { return _shadowWidth; }
set { _shadowWidth = value; }
}
private double _cornerRadius = 0;
public double CornerRadius
{
get { return _cornerRadius; }
set { _cornerRadius = value; }
}
public Brush Fill { get; set; }
private double _fillOpacity = 1.0;
public double FillOpacity
{
get { return _fillOpacity; }
set { _fillOpacity = value; }
}
public Brush Stroke { get; set; }
private double _strokeThickness = 1.0;
public Double StrokeThickness
{
get { return _strokeThickness; }
set { _strokeThickness = value; }
}
#endregion
#region Control Events
public BorderShadow()
{
InitializeComponent();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
double width = this.Width;
double height = this.Height;
for (int i = 0; i < _shadowWidth; i++)
{
Border newBorder = new Border();
width += 2;
height += 2;
newBorder.Width = width;
newBorder.Height = height;
newBorder.SetValue(Canvas.LeftProperty, (double)(-i - 1));
newBorder.SetValue(Canvas.TopProperty, (double)(-i - 1));
newBorder.BorderBrush = new SolidColorBrush(Color.FromArgb(SinAlpha(i), 0, 0, 0));
newBorder.BorderThickness = new Thickness(1);
newBorder.CornerRadius = new CornerRadius(_cornerRadius + (i + 1));
_borderShadows.Add(newBorder);
this.LayoutRoot.Children.Add(newBorder);
}
AddRectangleFill();
}
private void UserControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
double width = this.Width;
double height = this.Height;
_rectangleFill.Width = width;
_rectangleFill.Height = height;
for (int i = 0; i < _shadowWidth; i++)
{
Border borderShadow = _borderShadows[i];
width += 2;
height += 2;
borderShadow.Width = width;
borderShadow.Height = height;
}
}
#endregion
#region Public Events
#endregion
#region Public Methods
#endregion
#region Private Methods
private void AddRectangleFill()
{
if (Fill != null || Stroke != null)
{
_rectangleFill.Width = this.Width;
_rectangleFill.Height = this.Height;
if (Fill != null) _rectangleFill.Fill = Fill;
if (Stroke != null)
{
_rectangleFill.Stroke = Stroke;
_rectangleFill.StrokeThickness = StrokeThickness;
}
_rectangleFill.Opacity = FillOpacity;
_rectangleFill.RadiusX = _cornerRadius;
_rectangleFill.RadiusY = _cornerRadius;
this.LayoutRoot.Children.Add(_rectangleFill);
}
}
private byte SinAlpha(int i)
{
double maxAlpha = 48;
double alphaSlice = (maxAlpha * i) / _shadowWidth;
double alphaMultiplier = Math.Sin((Math.PI / 2) * (alphaSlice / maxAlpha));
byte alpha = Convert.ToByte(maxAlpha - (maxAlpha * alphaMultiplier));
return alpha;
}
#endregion
}
}
Be the first to rate this post
- Currently 0/5 Stars.
- 1
- 2
- 3
- 4
- 5