I haven't had much original content on here in a while so I thought that should change by putting up some short tutorials on building stuff using "WPF/E". And the obvious one to start with is a really simple video player (RSVP for short).
For an introduction to WPF/E, XAML and the programming model (JS) please refer to this article on MSDN which talks about WPF/E from a key scenario, web media usage - "WPF/E" for Web Media Scenarios.
What I use/you will need to follow this at home:
There are 3 steps for us to create this video player in WPF/E:
Opening Expression Design, we want a document with the same dimensions as our video player (e.g. 573 x 320). We will use the tool to create a skin which we will program against in Javascript. We need to add a background which we will replace with a MediaElement and two collections of shapes to represent our buttons (Play and full screen).
In the centre of the document, drag on a rectangle with quite a large size and set it's Opacity to 40% (In the properties palette on the right, try searching for it) and fill to White. Now do the same with an ellipse and using the Polyline tool (click and hold the Fountain pen icon to reveal the polyline tool on the left to create a triangle shape.
Currently, these are all separate shapes and we want to group them together so we can refer to them logically as a single item in code. Right-click and Group. In the layers pane expand the Layer 1 and double-click on [Group] and rename to PlayButton. This will make things easier when we export to XAML.
Now repeat the same process for a Full Screen button. I used a small rectangle and a large on inside a container rectangle. Name it FullScreen
This is in Expression Design format and we need to get it in XAML to render with the WPF/E plug-in. To do this:
File > Export... > Save As > XAML (video.xaml file name) > Select WPF/E export option > Export.
We now have a XAML file to program against. But it's only shapes on a Canvas, we need to create some interactivity so that when the user clicks the play button it disappears from view and plays the video.
Expression Blend doesn't currently support WPF/E friendly XAML and so we need to workaround this and use the tool as if it were a normal Windows EXE application. Create a new project, stick it somewhere handy, and link (under Project) to the video.xaml file.
To animate the PlayButton we need to create a new TimeLine - call it something like PlayAnimation. Blend now flips to recording mode which you can tell by the red outline on the design surface:
To animate the button we select it in the Timeline/Object hierarchy and advance the timeline on 1 or 2 seconds.
And modify the Opactity property and set it to 0. When the play button is pressed you will see the PlayButton fade from view.
Now, the workaround kicks in, as Blend puts the animation as a Resource in the XAML. This isn't supported in WPF/e and to fix it we need to move the animation directly into the Storyboard.
We need to turn this:
<Canvas.Resources><Storyboard x:Key="PlayAnimation"><DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="PlayButton" Storyboard.TargetProperty="(UIElement.Opacity)"><SplineDoubleKeyFrame KeyTime="00:00:01" Value="0"/></DoubleAnimationUsingKeyFrames></Storyboard></Canvas.Resources><Canvas.Triggers><EventTrigger RoutedEvent="FrameworkElement.Loaded"><BeginStoryboard Storyboard="{StaticResource PlayAnimation}"/></EventTrigger></Canvas.Triggers>
into this:
<Canvas.Triggers><EventTrigger RoutedEvent="FrameworkElement.Loaded"><EventTrigger.Actions><BeginStoryboard><Storyboard x:Name="PlayAnimation"><DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="PlayButton" Storyboard.TargetProperty="(UIElement.Opacity)"><SplineDoubleKeyFrame KeyTime="00:00:01" Value="0"/></DoubleAnimationUsingKeyFrames></Storyboard></BeginStoryboard></EventTrigger.Actions></EventTrigger></Canvas.Triggers>
Items in bold are new text (x:Key isn't support, x:Name is) and the Storyboard itself is just copied down and the Resources element removed.
One last bit of XAML. The Animation will being as soon the parent canvas element is loaded. To stop this from happening, we can add a BeginTime property to the Storyboard and set its time to "01:00:00" which means it will fire a day after first loading. Instead, we will initiate the animation in Javascript code.
I have used the Visual Studio web application plug-in and WPF/E template to create the container web project. John Rayner has details on installing and setting up your workstation for WPF/E
So, I have a WPFEJSApplication1 (or 1000 by now in my case :)) and I need to add the video.xaml file to the project and change the Default.html to reflect.
In the new aghost() declaration, replace:
plugin.xaml with video.xaml400 with 573 for width400 with 320 for height
One major part missing is the video. So, add a video to your project (I picked a large video with high res to show off full screen, any vanilla WMV9 video should do). In the video.xaml file we need to replace the black Path element which represents the background with a MediaElement:
<MediaElement x:Name="Media" Width="574" Height="321" Canvas.Left="-0.5" Canvas.Top="-0.5"Source="T2_720.wmv" AutoPlay="false" />
(AutoPlay is set to false, default is true to stop the video playing automatically)
Now, open the eventhandlers.js file and clear the file of the placeholder code. To get this sample working we need to hook up our buttons to event handlers, and set up the Loaded property in our root Canvas element (this is where we will set up the event handlers).
In the video.xaml file we need to add the following property:
<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="Untitled1"Loaded=root_Loaded>
And in the eventhandlers.js file we create the method:
function root_Loaded(sender, args) {}
We need to grab the PlayButton and we do this using the findName(string) method to pull it out of the XAML object model. And we hook up it's mouse up event to a function we will define in a sec:
var button = sender.findName("PlayButton");button.mouseLeftButtonUp = "javascript:handleMouseUp";var fsBtn = sender.findName("FullScreen");fsBtn.mouseLeftButtonUp = "javascript:leftMouseUpFSEvent";
The process is the same for invoking the Play() method on our video and Begin():
function handleMouseUp(sender, eventArgs) {//Grab the Media Element and call the Play() methodvar myMedia = sender.findName("Media");myMedia.Play();//Grab the animation and start itvar myAnimation = sender.findName("PlayAnimation");myAnimation.Begin();}
For the full screen we have to access the parent WPF/E control and set some properties and access it's height and width.
function leftMouseUpFSEvent(sender, eventArgs){//Find the parent WPFE control using getElementByIdvar wpfeC = document.getElementById("wpfeControl1");//Set the full screen property to true/false wpfeC.fullScreen = !wpfeC.fullScreen;//Grab the media element and set its height/width properties and make the FS button invisiblevar media = sender.findName("Media");media.Height = wpfeC.actualHeight;media.Width = wpfeC.actualWidth;var FS = sender.findName("FullScreen");FS.Opacity = 0;}
This is a functioning video player which will work cross-browser/cross-platform. I have hosted a version here for you to test (note: you must have the February CTP installed to view).
Really Simple Video Player in WPFE (Will take quite a while to download the 70 meg file which gives me a nice follow-on to async download) (and also available for download here).
Next up:
Adding more controls: pause, stop, volume, seeking, async progress. Better JS using prototype class inheritance for buttons, etc.