Creating a "Vista" shadow or halo in Silverlight

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:

SearchWithShadow

And without the halo:

SearchNoShadow

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

Posted by: Tim Miller
Posted on: 7/22/2008 at 9:32 PM
Tags: , , ,
Actions: E-mail | Kick it! | DZone it! | del.icio.us
Post Information: Permalink | Comments (16) | Post RSSRSS comment feed

Related posts

Comments

christian matchmaking us

Thursday, July 30, 2009 10:19 AM

christian matchmaking

This is what I have been looking for. At last i found it now. Thanks.

boiler cover review gb

Wednesday, September 30, 2009 1:35 AM

boiler cover review

Creating a quotVistaquot shadow or halo in Silverlight , intrigued me. I have recently set off to develop utilising Silverlight but am finding it is a large learning curve. My recent experience is with mysql, php, most linux based tools and flash. The problems of using Silverlight to get a satisfactory layout which functions rapidly in most of the established web browsers, Internet Explorer, Safari, Firefox and Chrome can be a great headache that is taking me many hours to solve. Engrossing to read your views and the comments in your website on Silverlight. I find the tutorial websites and Microsofts Silverlight site are inert and cover the same items, comments and dialog in web logs often references actual methods to resolve issues which takes me through the learning curve more rapidly. Thank you for the note, it has assisted in a moderate way to take me through the migration.

personal loans us

Friday, October 16, 2009 5:55 AM

personal loans

Nice post . keep up the good work

personal loans us

Saturday, October 31, 2009 3:07 AM

personal loans

Do you have any more info on this?

cash loans us

Monday, November 02, 2009 1:10 PM

cash loans

Interesting ... as always - is your blog making any cash advance ? ;)

payday loans us

Friday, November 27, 2009 11:37 AM

payday loans

Searching for this for some time now - i guess luck is more advanced than search engines Smile

payday loans us

Wednesday, December 16, 2009 8:53 AM

payday loans

Do you have any more info on this?

lee le cn

Friday, December 18, 2009 2:54 PM

lee le

<P>this really assists, today i receive the troubles and i donot know how to work out,
i research bing and discovered your blog,
thanks once more</P><P>just one thing, can i post this entry on my blog? i will add the source and credit to your site.</P><P>regards!</P>

dating tip for guys us

Friday, December 18, 2009 6:04 PM

dating tip for guys

This is such a great resource that you are providing and you give it away for free. I love seeing websites that understand the value of providing a quality resource for free. It’s the old what goes around comes around routine.

Niche Blueprint 2.0 Review us

Wednesday, December 30, 2009 1:52 PM

Niche Blueprint 2.0 Review

I love reading your posts. I wish you a Happy New Year!

Alaska Payday Loans us

Monday, January 04, 2010 5:04 AM

Alaska Payday Loans

Like your writing! Still you can do some things to improve it.

payday cash advance us

Saturday, January 23, 2010 6:51 AM

payday cash advance

Like you've never seen this before .. c'mon let's be serious

payday loans us

Sunday, January 24, 2010 4:46 AM

payday loans

Just .. Thank you for your help!

Loans in OH us

Monday, February 01, 2010 12:56 PM

Loans in OH

Let me tell you the secret that has led me to my goal. My strength lies solely in my tenacity.

acai berry review us

Wednesday, February 24, 2010 3:11 AM

acai berry review

If you realize that all things change, there is nothing you will try to hold on to... there is nothing you cannot achieve.

10 Articles ph

Monday, March 08, 2010 9:56 AM

10 Articles

Great blog indeed! I never heard about this shadow effect before. Thanks for giving the time to share this very useful information in this blog. Keep up the good work!

Add comment


(Will show your Gravatar icon)  

  Country flag

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



Live preview

Wednesday, March 10, 2010 6:33 PM