Simple Media Player in Silverlight (JavaScript and C# versions)
In my last blog post, I listed a pointer to a walkthrough to help learn Silverlight and Expression Blend located here. The walkthrough is for Silverlight 1.0, with the code in JavaScript. If you have not had a chance to play with Silverlight or Expression Blend, I highly recommend going through the walkthrough. You will understand how Silverlight works after doing so. In addition, I made the following modifications to the end-result code from the Walkthrough to further :
- Hooked the MediaEnded event on the MediaElement object to reset the UI when the content ends.
- Updated onFullScreenChanged event to display correctly in full screen mode.
- Re-position and show buttons transparently over video when in full screen mode.
- Play an animation on the MediaElement when the stop and return to beginning button is clicked.
Attached to the end of this blog post is the updated Silverlight 1.0 RC version (August 2007) of the code in JavaScript. Also attached is a Silverlight 1.1 Alpha Refresh (August 2007) version of the same functionality in C# to allow for comparison. More discussion of the C# version is below but first here are additional details on the modifications I made to the JavaScript version.
MediaEnded event (and return to the begining of the video)
This is pretty easy to do. I added an event to the MediaElement in the XAML:
<MediaElement x:Name="mediaElement" MediaEnded="MediaEnded" ......
Here is the JavaScript MediaEnded event handler:
function MediaEnded(sender, eventArgs)
{
if (sender.name == "mediaElement")
{
sender.findName("mediaElementStoryboard").begin();
//Reset media to begining
sender.Position = "00:00:00"
// Swap Pause and Play graphics since media has ended
var playTriangle = sender.findName("playTriangle");
var leftPauseLine = sender.findName("leftPauseLine");
var rightPauseLine = sender.findName("rightPauseLine");
playTriangle.opacity = 1;
leftPauseLine.opacity = 0;
rightPauseLine.opacity = 0;
}
}
I added a simple RotateTransform and ScaleTransform Storyboard animation to the media element to make resetting the media to the beginning less jarring and to demonstrate that just about anything can be animated. Resetting the media is a matter of setting the position to the beginning in this code: sender.Position = "00:00:00". Finally, I reset the play button to display the Play symbol and hide the Pause symbol.
onFullScreenChanged Event (and button reposition)
The tutorial at the link above describes how to hook into the onFullScreenChanged event quite well so I won't go into it here except to highlight the code changes I made. Instead of making the buttons disappear when in full-screen mode, I instead set the Opacity to .4 for a transparent look and reposition to the bottom of the screen so that the controls are still accessible when in full screen mode. I change the canvas color to white in full screen mode as well as perform the calculations correctly when returning from full-screen mode. Here is the updated code.
function onFullScreenChanged(sender, args)
{
// Get a reference to the Silverlight control that is hosted in the HTML page.
var silverlightControl = sender.getHost();
// Get a reference to the Canvas that contains all of the buttons.
var buttonPanel = sender.findName("buttonContainer");
// Get a reference to the media player.
var mediaElement = sender.findName("mediaElement");
var canvasMain = sender.findName("canvasMain");
if (silverlightControl.content.fullScreen == true)
{
// Since the Silverlight control is in fullscreen mode, make the buttons invisible.
buttonPanel.opacity = .4;
buttonPanel.setValue("Canvas.Left",(silverlightControl.content.actualWidth / 2) - 260);
buttonPanel.setValue("Canvas.Top",silverlightControl.content.actualHeight - 100);
// Set the media player to go full screen with border
mediaElement.width = silverlightControl.content.actualWidth - 16;
mediaElement.height = silverlightControl.content.actualHeight - 16;
canvasMain.width = silverlightControl.content.actualWidth ;
canvasMain.height = silverlightControl.content.actualHeight;
canvasMain.background = "White"
}
else
{
// Since the Silverlight control is back to its original mode, make buttons visible.
buttonPanel.opacity = 1;
buttonPanel.setValue("Canvas.Left",46.0);
buttonPanel.setValue("Canvas.Top",411.5);
//Hard-code back to original design-time values to keep it simple for fix size video player
mediaElement.width = 561;
mediaElement.height = 396.5;
canvasMain.background="#FF000000"
}
}
C# Version
The C# version of the sample developed in the Silverlight 1.0 JavaScript walkthrough has the same functionality. I created it using Visual Studio 2008 Beta 2 and Expression Blend 2 August Preview. The install page for Expression Blend 2 August Preview is located here. It has installation instructions for Windows Vista and Windows XP (the only difference is to install .NET 3.0 on XP) including links. I installed all of the following (Visual Studio Team System instead of Visual Studio 2005 Express) to set up my environment.
- Install a version of Silverlight:
- Install Expression Blend 2 August Preview* (25 MB)
- Do one of the following:
- Install Visual Studio 2005 Express for developing JavaScript Silverlight-based applications.
- Install Visual Studio 2008 for developing managed Silverlight-based applications.
- Install Silverlight Tools Alpha for Visual Studio 2008.
If you don't want to install Visual Studio 2008, you can still take a look at the xaml and c# files for the Silverlight 1.1 version as well as run it int the browser. Functionally and appearance-wise, the two versions are the same. The XAML is almost identical except for the following additional attribute on the outer Canvas tag:
<Canvas .... x:Class="FixedSizeMediaPlayer_CSharp.Page;assembly=ClientBin/FixedSizeMediaPlayer_CSharp.dll"
The x:Class attribute tells the Silverlight 1.1 loader what assembly to load for the C# code. Otherwise, the XAML is essentially the same.
From a coding perspective, C# is compiled and hence strongly typed. Any XAML elements that have an x:Name attribute appear in Intellisense. This happens via the design-time support in Silverlight 1.1 that auto-generates the declarations for you in a hidden file. "FindName" is still called just like in the JavaScript version in the auto-generated partial class file in the InitializeComponent() method. Here is the auto generated file (that is dynamically updated as you add XAML elements with x:Name attributes):
//------------------------------------------------------------------------------
// auto-generated
// This code was generated by a tool.
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// /auto-generated
//------------------------------------------------------------------------------
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace FixedSizeMediaPlayer_CSharp
{
public partial class Page
{
// variable declarations
Storyboard playButtonStoryboard;
Storyboard stopButtonStoryboard;
Storyboard fullScreenButtonStoryboard;
Storyboard mediaElementStoryboard;
MediaElement mediaElement;
Canvas buttonContainer;
Canvas playButton;
Rectangle outerRectangle;
Rectangle innerRectangle;
Rectangle playBtnGlassRectangle;
Path playTriangle;
Path leftPauseLine;
Path rightPauseLine;
Canvas stopButton;
Rectangle outerRectangle1;
Rectangle innerRectangle1;
Rectangle stopBtnGlassRectangle;
Rectangle stopRectangle;
Path stopTriangleBeginning;
Canvas fullScreenButton;
Rectangle outerRectangle2;
Rectangle innerRectangle2;
Rectangle fullScreenBtnGlassRectangle;
private void InitializeComponent()
{
playButtonStoryboard = this.FindName("playButtonStoryboard") as Storyboard;
stopButtonStoryboard = this.FindName("stopButtonStoryboard") as Storyboard;
fullScreenButtonStoryboard = this.FindName("fullScreenButtonStoryboard") as Storyboard;
mediaElementStoryboard = this.FindName("mediaElementStoryboard") as Storyboard;
mediaElement = this.FindName("mediaElement") as MediaElement;
buttonContainer = this.FindName("buttonContainer") as Canvas;
playButton = this.FindName("playButton") as Canvas;
outerRectangle = this.FindName("outerRectangle") as Rectangle;
innerRectangle = this.FindName("innerRectangle") as Rectangle;
playBtnGlassRectangle = this.FindName("playBtnGlassRectangle") as Rectangle;
playTriangle = this.FindName("playTriangle") as Path;
leftPauseLine = this.FindName("leftPauseLine") as Path;
rightPauseLine = this.FindName("rightPauseLine") as Path;
stopButton = this.FindName("stopButton") as Canvas;
outerRectangle1 = this.FindName("outerRectangle1") as Rectangle;
innerRectangle1 = this.FindName("innerRectangle1") as Rectangle;
stopBtnGlassRectangle = this.FindName("stopBtnGlassRectangle") as Rectangle;
stopRectangle = this.FindName("stopRectangle") as Rectangle;
stopTriangleBeginning = this.FindName("stopTriangleBeginning") as Path;
fullScreenButton = this.FindName("fullScreenButton") as Canvas;
outerRectangle2 = this.FindName("outerRectangle2") as Rectangle;
innerRectangle2 = this.FindName("innerRectangle2") as Rectangle;
fullScreenBtnGlassRectangle = this.FindName("fullScreenBtnGlassRectangle") as Rectangle;
}
}
}
I have to admit that I found the strongly-typed nature of Silverlight 1.1 easier to work with, but I admittedly spend more time in C# than in JavaScript so I am probably a bit biased:-) There are a few things that "feel' more natural in JavaScript such as working with the HTML DOM. However, Silverlight 1.1 provides full access to the HTML DOM from C# via the System.Windows.Browser.HtmlDocument object. For example, to find an HTML input element in the DOM with an ID of "SourceURL" to set the Source property on an MediaElement you could write code like this:
MediaElement me = (MediaElement)this.FindName("mediaPlayer");
System.Windows.Browser.HtmlDocument hdoc;
hdoc = HtmlPage.Document;
me.Source = new Uri(hdoc.GetElementByID("SourceURL").GetProperty<string>("value"));
me.Play();
The other Silverlight C# class to point out is System.Windows.Interop.BrowserHost. The BrowserHost object contains the Silverlight control and I use it to determine the width and height when playing in full screen mode:
mediaElement.Width = BrowserHost.ActualWidth - 16;
mediaElement.Height = BrowserHost.ActualHeight - 16;
I hope that you find the examples useful in your journey to learn Silverlight!
Note: This is sample code for demonstration purposes and not meant for production use.
Comments
Anonymous
October 27, 2007
I had created simple project of Silverlight 1.1 using Visual studio 2008. Then i deployed it on my personal website.But it is not displaying anything when i run the testpage.html. Could you tell me what could be the reason of failure. Thanks in advance...Anonymous
December 14, 2007
Nice sample, maybe you should have mentionned somewhere (at least I didn't see it) that you have to have "bear.wmv" in the app dir.