Silverlight Toolbar Tutorial

Back To: Silverlight Tutorials

The Application

This is "Yet Another Silverlight Toolbar". What sets this toolbar apart is that it is composed of only a Toolbar and a Box. The box is simply placed in the toolbar multiple times to create the elements on the Toolbar.

This shows the files in the project. The application is primarily composed of Page.xaml that contains the toolbar and Box.xaml that contains the element used to represent the menu items. 

Page.xaml: 

The picture above shows how the toolbar looks when viewed in Expression Blend. All the elements are easily editable. Basically it is comprised of a ToolBar that scrolls to the left and the right. The JavaScript method (SetToolbarWindowClip) will apply a "Clip" that will only show a portion of the Toolbar.

The graphic above shows the outline of the elements.

Box.xaml

As you can see the Box.xaml file is simply an image with a reflected image below it. This file is also easily editable in Expression Blend.

The Animation

The animation is simple and straightforward. Page.xaml contains a storyboard:

<Canvas.Resources>
<Storyboard x:Name="Movebar">
<DoubleAnimation x:Name="animateToolbar" Duration="0:0:0.5" Storyboard.TargetName="ToolBar"
Storyboard.TargetProperty="(Canvas.Left)" />
</Storyboard>
</Canvas.Resources>

Page.xaml.js contains this reference to the storyboard and the animation contained in the storyboard:

storyboard = rootElement.findName("Movebar");
animation = rootElement.findName("animateToolbar");

After a button is pressed, scrollPosition is calculated. The animation destination value (animation.To) is set to the current scrollPosition and the storyboard is triggered to run the animation.

animation.To = scrollPosition;
storyboard.Begin();

Customizing the Application

//Array of pictures
var objPicture = new Array();
objPicture[0] = "adef.png";
objPicture[1] = "bells.png";
objPicture[2] = "DesignWithSilverlight.png";
objPicture[3] = "nibbles.png";
objPicture[4] = "silverlight.png";
objPicture[5] = "silverlightCream.png";
 
//Array of websites
var objWebsite = new Array();
objWebsite[0] = "http://ADefwebserver.com";
objWebsite[1] = "http://ValeriesWeddings.com";
objWebsite[2] = "http://DesignWithSilverlight.com";
objWebsite[3] = "http://www.nibblestutorials.net";
objWebsite[4] = "http://Silverlight.net";
objWebsite[5] = "http://SilverlightCream.com";

Simply add a picture and a website to the appropriate array to customize the items.

var NumberOfButtons = 5;
var NumberOfButtonsToShow = 4;

You will also need to change the amount of buttons and optionally how many you want to show at one time. The left and right navigation buttons will show up automatically when needed.

Source Code:

Page.xaml.js:

if (!window.ToolBarTest)
    window.ToolBarTest = {};
 
ToolBarTest.Page = function() 
{
}
// Set the size and number of buttons for the ToolBar
var ButtonSize = 55;
var NumberOfButtons = 5;
var NumberOfButtonsToShow = 4;
 
//Array of pictures
var objPicture = new Array(); 
objPicture[0] = "adef.png";
objPicture[1] = "bells.png";
objPicture[2] = "DesignWithSilverlight.png";
objPicture[3] = "nibbles.png";
objPicture[4] = "silverlight.png";
objPicture[5] = "silverlightCream.png";
 
//Array of websites
var objWebsite = new Array(); 
objWebsite[0] = "http://ADefwebserver.com";
objWebsite[1] = "http://ValeriesWeddings.com";
objWebsite[2] = "http://DesignWithSilverlight.com";
objWebsite[3] = "http://www.nibblestutorials.net";
objWebsite[4] = "http://Silverlight.net";
objWebsite[5] = "http://SilverlightCream.com";
 
var ToolBar;
var ToolBarWindow;
var objBox = new Array(); 
var CurrentLocation = 0;
var scrollPosition = 0;
var LeftButton;
var RightButton;
 
var storyboard;
var animation;
 
var ToolBarWidth = NumberOfButtonsToShow * ButtonSize;
 
ToolBarTest.Page.prototype =
{    
 
    handleLoad: function(control, userContext, rootElement) 
    {    
        // Get a reference to the various XAML elements
        ToolBar = rootElement.findName("ToolBar");
        ToolBarWindow = rootElement.findName("ToolBarWindow");
        LeftButton = rootElement.findName("LeftButton");
        RightButton = rootElement.findName("RightButton");
 
        storyboard = rootElement.findName("Movebar");
        animation = rootElement.findName("animateToolbar");
        
        // Add the buttons to the Toolbar
        for(i = 0; i <= NumberOfButtons; i++)
        {
            objBox[i] = new box("box" + i, ToolBar, CurrentLocation, objPicture[i], objWebsite[i]);
            CurrentLocation = CurrentLocation + ButtonSize;
        }
        
        // Set the Clipping on the ToolBarWindow (Canvas)
        // This causes only a portion of the ToolBar (that is also on the ToolBarWindow Canvas) to show
        SetToolbarWindowClip(ToolBarWindow, ToolBarWidth);
        
        // Always hide the LeftButton on page load
        LeftButton.visibility = "Collapsed";
                
        // Hide the RightButton if it is not needed
        if (NumberOfButtons * ButtonSize <= ToolBarWidth)
        {
            RightButton.visibility = "Collapsed";
        }
        else
        {
             // Set the position of the RightButton
            RightButton["Canvas.Left"] = ToolBarWidth + (ButtonSize/2);
        }
        
        // Attach event handlers to Left and Right buttons
        LeftButton.addEventListener("MouseLeftButtonDown", Silverlight.createDelegate(this, this.handleMouseDown));
        RightButton.addEventListener("MouseLeftButtonDown", Silverlight.createDelegate(this, this.handleMouseDown));
    },
 
        handleMouseDown: function(sender, eventArgs)
        {          
            if(sender.Name == "LeftButton") // LeftButton
            {
                // Only advance Toolbar (scrollPosition) if it is not already at the the 
                // first Button
                if(scrollPosition != 0)
                {
                    // Move the scrollPosition
                    scrollPosition+=ButtonSize;
 
                    // If the LeftButton is clicked then the RightButton needs to show
                    RightButton.visibility = "Visible";
                    
                    // Do not show LeftButton if the first Button is showing
                    if(scrollPosition == 0)
                    {
                        LeftButton.visibility = "Collapsed";
                    }
                    else
                    {
                        LeftButton.visibility = "Visible";
                    }
                }
            }
            
            if(sender.Name == "RightButton") // RightButton
            {
                // Only advance Toolbar (scrollPosition) if there are Buttons to show
                if(scrollPosition >= -((NumberOfButtons * ButtonSize) - ToolBarWidth))
                {
                    // Move the scrollPosition
                    scrollPosition-=ButtonSize;
                    // If the RightButtonis clicked then the LeftButton needs to show
                    LeftButton.visibility = "Visible";
                    
                    // Do not show RightButton if the last Button is showing
                    if(scrollPosition == -(((NumberOfButtons + 1) * ButtonSize) - ToolBarWidth))
                    {
                        RightButton.visibility = "Collapsed";
                    }
                    else
                    {
                        RightButton.visibility = "Visible";
                    }
                }
            }
            
            // Move the ToolBar by setting it to the current scrollPosition
        animation.To = scrollPosition;
        storyboard.Begin();
 
        } 
}
 
function SetToolbarWindowClip(objToolBarWindow, dblToolBarWidth)
{
    // Since the RectangleGeometry cannot be edited visually in Expression Blend
    // It is ok to create it dynamically
    var xamlFragment;
    // Retrieve a reference to the plug-in.
    var plugin = objToolBarWindow.getHost();  
    // Define a XAML fragment for RectangleGeometry
    xamlFragment = '<RectangleGeometry Rect="0,0,xxx,100" />';
    // Set the width of the RectangleGeometry to ToolBarWidth
    xamlFragment = xamlFragment.replace("xxx", dblToolBarWidth);
    // Create the XAML fragment
    ToolBarClip = plugin.content.createFromXaml(xamlFragment);
    // Set the Clip of the ToolbarWindow (Canvas) to the XAML fragment
    objToolBarWindow.Clip = ToolBarClip;
}

Box.xaml.js:

// Michael Washington
// Silverlight Tutorials
// http://www.adefwebserver.com/DotNetNukeHELP/Misc/Silverlight/
 
// Adapted from Justin-Josef Angel's
// "Silverlight Controls - The path to reusable XAML"
// http://blogs.microsoft.co.il/blogs/justinangel/archive/2007/08/14/Silverlight-Controls-_2D00_-The-path-to-reusable-XAML.aspx
 
// This JavaScript file defines the object "box"
 
 
box = function(ID, Parent, XLocation, imgPicture, strWebsite)
{
 
    this._ID = ID + "_";
    this._parent = Parent; 
    this._XLocation = XLocation;
    this._imgPicture = imgPicture;
    this._strWebsite = strWebsite;
    this._host = this._parent.getHost();
    this.Element;
   
    // The first step is to retrive the XAML content for the "box"
    this.StartXamlDownload();
}
 
box.prototype = 
{   
 
    _findNameByXamlID : function(nameInXamlFile)
    {
        return this._parent.findName(this._getIdFor(nameInXamlFile)); 
    },
    
    _getIdFor : function(nameInXamlFile)
    {
        return this._ID + nameInXamlFile;        
    },
    
    StartXamlDownload : function()
    {
        // A Silverlight "downloader" object is used to retrieve the "box.xaml" file that contains
        // the XAML for the "box"
        // A delegate is created that will call the "XamlDownloadCompleted" method when the 
        // download is completed
        var xamlDownloader = this._host.createObject("downloader");
        xamlDownloader.open("GET", "box.xaml");
        xamlDownloader.addEventListener("completed", Silverlight.createDelegate(this, this.XamlDownloadCompleted));
        xamlDownloader.send();        
    },
    
    DownloadPicture : function()
    {
        // A Silverlight "downloader" object is used to retrieve the Picture
        // A delegate is created that will call the "PictureDownloadCompleted" method when the 
        // download is completed
        var xamlDownloader = this._host.createObject("downloader");
        xamlDownloader.open("GET", "images/" + this._imgPicture);
        xamlDownloader.addEventListener("completed", Silverlight.createDelegate(this, this.PictureDownloadCompleted));
        xamlDownloader.send();        
    },
    
    XamlDownloadCompleted : function(sender, eventArgs)
    {
        // The download of "box.xaml" has been completed
        // "sender.ResponseText" contains the contents of "box.xaml"
        var originalXaml = sender.ResponseText;
 
        // In order to avoid name collisions, the name of each "box" object will be replaced
        // with a name that begins with the ID that was passed in the object constructor
        originalXaml = originalXaml.replace(/Name="/g, "Name=\"" + this._ID);
                
        // The altered "box.xaml" is used to create a XAML object
        var plugin = sender.getHost(); 
        var newElement = plugin.content.createFromXaml(originalXaml)
 
    // Set Element to the XAML object so that it can be manipulated 
    this.Element = newElement;
 
        // The "box" will now be added to the main Canvas
        
        // The XML object is added to the element passed in the constructor
        this._parent.children.add(newElement);
 
        // Now that the "box" has been added to the main Canvas
        // the "BoxTitle" will be altered and the "box" position will be set
        this._setControlReferences(); 
        
        // Set the picture
        // The Downl;oader wil be used because it allows us to know when the image is ready
        // If we do not use the Downloader we may try to use an image that is not yet avalaible
        this.DownloadPicture();
    }, 
    
    _setControlReferences : function()
    {          
        this._box = this._findNameByXamlID("box");
        this._box["Canvas.Left"] = this._XLocation;
        this._box["Canvas.Top"] = 10;
 
    this._box.addEventListener("MouseLeftButtonDown", Silverlight.createDelegate(this, this.handleMouseDown));
    },
    
    PictureDownloadCompleted : function(sender, eventArgs)
    {
        // The download of the picture has been completed
        // setSource(sender, "") will set the source for the Thumbnail
        // to value of "sender" which is the image
        var originalXaml = sender.ResponseText;
        var Thumbnail = this._findNameByXamlID("Thumbnail");
        Thumbnail.setSource(sender, "");
        //Also set the Reflection Image
        var Thumbnail_Reflection = this._findNameByXamlID("Thumbnail_Reflection");
        Thumbnail_Reflection.setSource(sender, "");
 
    }, 
    
    handleMouseDown: function(sender, eventArgs)
    {     
        // Navigate to the website
        window.location.href = this._strWebsite;   
    } 
       
}
 

Download the complete source code here: SilverlightToolBarjs.zip

Back To: Silverlight Tutorials

Also See:


http://ADefwebserver.com

[About the author]