Click here to Skip to main content
Click here to Skip to main content

Silverlight2 Lightbox

, 28 Apr 2008 Ms-PL
Rate this:
Please Sign up or sign in to vote.
A Silverlight2 lightbox control

Introduction

TeamLive (the project I have been working on recently) blends ASP.NET, Ajax and Silverlight in a number of places and I was interested to see how far I could push the HTML/Silverlight blend - the lightbox seemed like a good component for my experiment.

For those of you wondering, a Lightbox is an effect that fades the page in the background to show you new content in the foreground.

This article isn't intended to be a Silverlight tutorial. If you are new to this technology, then I recommend reading some of the beginners' tutorials before using this code.

Background

TeamLive blends ASP.NET, Ajax and Silverlight in a number of places. E.g. during a multi-file upload, we adjust the OBJECT's styles giving it more screen space for displaying the progress bars.

image

One of the controls I have been working on for the next iteration of TeamLive is a lightbox to help users navigate their image grids.

Some of the requirements for the lightbox are listed below:

  • Only load the big image if needed (duh!)
  • Small xap (the js lightboxes we've used in the past have required a lot of js and/or associated images) - this xap is only 8K
  • Only one Silverlight lightbox object per page (we didn't want lots of objects being created)
  • Simple to use (drop a xap on a page and call some js)
  • Degrade cleanly when Silverlight 2 is not present

Demo

If you have Silverlight 2 installed, visit http://www.devprocess.com and click one of the images...

Back?

I hope you saw something like this:

image

If you just got an ugly window.open, then you don't have Silverlight 2.

Using the Code

Firstly, the PageBlanket Silverlight class. A simple class that can be used to disable the page with an overlay.

A similar technique is used by the modal popup overlay (see the ModalPopup on the AjaxControlToolkit: http://www.asp.net/AJAX/AjaxControlToolkit/Samples/ModalPopup/ModalPopup.aspx)

/// <summary>
/// PageBlanket covers a page with a partially transparent div
/// to prevent users interacting with the page - can be used to simulate a modal
/// dialog
/// </summary>
public class PageBlanket
{
    HtmlElement _blanket = null;
    /// <summary>
    /// Lazy initialization on first call
    /// </summary>
    private void Initialize()
    {
        if (_blanket == null)
        {
            //create a div that will take up the whole page and 
            //cover the content underneath
            _blanket = HtmlPage.Document.CreateElement("div");

            HtmlPage.Document.Body.AppendChild(_blanket);
            _blanket.SetStyleAttribute("position", "fixed");
            _blanket.SetStyleAttribute("top", "0px");
            _blanket.SetStyleAttribute("left", "0px");
            _blanket.SetStyleAttribute("height", "100%");
            _blanket.SetStyleAttribute("width", "100%");
            _blanket.SetStyleAttribute("backgroundColor", "#808080");
            _blanket.SetStyleAttribute("filter", "alpha(opacity=50)");
            _blanket.SetStyleAttribute("opacity", "0.5");
            _blanket.SetStyleAttribute("z-index", "3");
            _blanket.SetStyleAttribute("display", "none");
        }
    }

    /// <summary>
    /// Show the blanket and cover the page
    /// </summary>
    public void Show()
    {
        //just in case not init'ed
        Initialize();
        //clear display attribute to show the blanket
        _blanket.SetStyleAttribute("display", "");
    }

    /// <summary>
    /// Hide the blanket again
    /// </summary>
    public void Hide()
    {
        //hide the blanket
        _blanket.SetStyleAttribute("display", "none");
    }
}

Page blanket creates a div, sets the style, jams it in the page, and toggles the display style to show/hide the div. This effectively disables the page while we do the Silverlight stuff.

Dynamically showing/hiding the Silverlight control turned out to be harder.

Firefox gets upset if you start moving the control around, changing zIndex, altering display style dynamically.

I was getting working code in Internet Explorer 7 and “Trying to get unsupported property on scriptable plugin object!” errors in Firefox.

The solution I found (works on Internet Explorer 7, Firefox2 and Safari (not tested on anything else yet)) was to set a small Width and Height (yeah, yeah - I know). I make sure I set the style of the object at the start (changing position and zIndex dynamically in the C# screwed up the scriptableobject).

The Lightbox Code

Note it positions the lightbox in the center of the screen. Originally the code positioned the lightbox over the item that launched it - but it never looked quite right so I tried centering the lightbox. I’m not sure it’s much better in the center - so I’m waiting for inspiration.

using System;
using System.Collections.Generic;
using System.Linq;
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;
using System.Windows.Browser;
using System.Windows.Media.Imaging;

namespace dpLightbox
{
    [ScriptableType]
    public partial class Page : UserControl
    {

        public Page()
        {
            InitializeComponent();
            Loaded += new RoutedEventHandler(Page_Loaded);
            //keep the lightbox in the center if page is resized
            HtmlPage.Window.AttachEvent("onresize", new EventHandler(Window_Resize));
        }

        void Window_Resize(object sender, EventArgs e)
        {
            PositionToCenter();
        }

        void Page_Loaded(object sender, RoutedEventArgs e)
        {
            //register for javascript control
            HtmlPage.RegisterScriptableObject("LightboxController", this);

            //the close button
            bClose.MouseEnter += new MouseEventHandler(bClose_MouseEnter);
            bClose.MouseLeave += new MouseEventHandler(bClose_MouseLeave);
            bClose.MouseLeftButtonUp += 
		new MouseButtonEventHandler(bClose_MouseLeftButtonUp);
        }

        bool closing = false;
        /// <summary>
        /// Close the lightbox
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void bClose_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            closing = true;
            rCloseGlow.Opacity = 0.0;
            sbLightbox.Completed += new EventHandler(sbLightbox_Completed);
            sbLightbox.AutoReverse = true;
            sbLightbox.Stop();
            sbLightbox.Begin();
            sbLightbox.Seek(new TimeSpan(0, 0, 0, 0, 500));
        }

        void sbLightbox_Completed(object sender, EventArgs e)
        {
            if (closing)
            {
                _blanket.Hide();

                Width = 0;
                Height = 0;
                HtmlPage.Plugin.SetStyleAttribute("width", "1px");
                HtmlPage.Plugin.SetStyleAttribute("height", "1px");
            }

            closing = false;
        }

        void bClose_MouseLeave(object sender, MouseEventArgs e)
        {
            rCloseGlow.Opacity = 0.0;

        }

        void bClose_MouseEnter(object sender, MouseEventArgs e)
        {
            rCloseGlow.Opacity = 1.0;
        }

        double paddingTop = 55;
        double padding = 25;
        PageBlanket _blanket = new PageBlanket();
        [ScriptableMember]
        public void showLightbox(string imgTitle, string imgSrc, 
			double imgWidth, double imgHeight)
        {
            _blanket.Show();

            txtTitle.Text = imgTitle;
            imgMain.Source = new BitmapImage
		(new Uri(imgSrc, UriKind.RelativeOrAbsolute));
            imgMain.ImageFailed += new ExceptionRoutedEventHandler(imgMain_ImageFailed);

            //setup the lightbox size
            double dWidth = imgWidth + (padding * 2);
            double dHeight = imgHeight + (padding + paddingTop);

            Width = dWidth;
            Height = dHeight;

            kfWidth.Value = dWidth;
            kfHeight.Value = dHeight;

            HtmlPage.Plugin.SetStyleAttribute("height", Height.ToString() + "px");
            HtmlPage.Plugin.SetStyleAttribute("width", Width.ToString() + "px");

            sbLightbox.Stop();
            sbLightbox.Seek(new TimeSpan(0));
            sbLightbox.AutoReverse = false;
            sbLightbox.Begin();

            HtmlPage.Plugin.SetStyleAttribute("display", "");

            PositionToCenter();
        }

        void imgMain_ImageFailed(object sender, ExceptionRoutedEventArgs e)
        {
            //the developer needs to decide what should happen here
            //empty lightbox?  don't show the lightbox?
        }

        private void PositionToCenter()
        {
            Size clientBounds = BrowserHelper.GetClientBounds();
            Point ptScrollPos = BrowserHelper.GetScrollPosition();

            double dTop = ptScrollPos.Y + ((clientBounds.Height - Height) / 2);
            double dLeft = ptScrollPos.X + ((clientBounds.Width - Width) / 2);

            HtmlPage.Plugin.SetStyleAttribute("top", dTop.ToString() + "px");
            HtmlPage.Plugin.SetStyleAttribute("left", dLeft.ToString() + "px");
        }
    }
}

Using the Lightbox

In your aspx:

<asp:Silverlight ID="slLb" runat="server" 
	Source="~/ClientBin/dpLightbox.xap" Version="2.0" 
Width="1px" Height="1px" PluginBackground="Transparent" Windowless="true" 
style="position:absolute;z-index:4;">
    <PluginNotInstalledTemplate></PluginNotInstalledTemplate>
</asp:Silverlight>

The PluginNotInstalledTemplate gets rid of the install Silverlight 2 prompt when Silverlight 2 isn’t installed - which is nice as the Lightbox isn’t essential functionality.

Put this bit of JavaScript in the head to simplify usage. This gets the Silverlight xap to show the lightbox or (shudder) a window.open if Silverlight 2 isn’t there.

<script type="text/javascript">
    function lightbox(imgTitle,imgSrc,imgWidth,imgHeight)
    {
        var lbContent=document.getElementById("slLb").Content;
        if(lbContent!=null)
        {
            lbContent.LightboxController.showLightbox
			(imgTitle,imgSrc,imgWidth,imgHeight);
        }
        else
        {
            window.open(imgSrc,"noSilverlight","menubar=no,
			toolbar=no,height="+imgHeight+",width="+imgWidth);
        }
    }   
</script>

Showing a lightbox - to show a lightbox call the function above.

<a href="javascript:lightbox('TeamLive designer',
    'http://www.devprocess.com/App_Themes/Default/lb_designer.jpg',600,296);">

<img src="App_Themes/default/designer.jpg" class="photosmall" 
    width="264" height="130" alt="Screenshot from devProcess TeamLive" />

</a>

TeamLive

You can keep up to date with any updates (I will also try to make them here) at our blog: TeamLive Blog.

History

  • 28th April, 2008: Article submitted

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

Share

About the Author

Tim Mason
Architect Development Process Ltd.
United Kingdom United Kingdom
Chief architect and project lead for many devProcess projects, including TeamLive.
 
http://www.TeamLive.com

Comments and Discussions

 
QuestionSilverlight 2 ? Pinmemberjoysnlove6-Jan-09 15:05 
Generalnice PinmemberAbhijit Jana28-Apr-08 22:06 
GeneralLittle bug PinmemberRimas28-Apr-08 20:32 
GeneralRe: Little bug PinmemberTim Mason29-Apr-08 0:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141216.1 | Last Updated 28 Apr 2008
Article Copyright 2008 by Tim Mason
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid