| Comments

I’ve just finished updating my modification of Joel’s original concept.  Joel had a really great base for me to build off of and used styling and templates to create simple controls for a standard Silverlight media player that could be embedded.  I took his sample and made some minor adjustments to accommodate automatic sizing as well as make it a bit more parameter-driven.  The end result was (what I think at least) a fairly nice player that could be flexible if needed:

Joel made great use of styling primitive controls to be able to leverage core functionality rather than building it all himself.  One of those controls used was the ToggleButton (the play/pause feature) which makes sense for the implementation.  In the beta 1 version of styling we were able to use different styles for MouseOver states for checked/unchecked features.  A snippet of the styling XAML looked like this:

<Storyboard x:Key="MouseOver Unchecked State">
    <DoubleAnimation Duration="0:0:0.1" Storyboard.TargetName="playSymbol" 
Storyboard.TargetProperty="Opacity" To="1" /> <DoubleAnimation Duration="0:0:0.1" Storyboard.TargetName="pauseSymbol"
Storyboard.TargetProperty="Opacity" To="0" /> </Storyboard>

This worked fine in beta 1.  Beta 2 introduces the VisualStateManager model which is an exciting new feature for developers and designers.  Opening the video player project in the latest tools had some things blow up for us…no problem, let’s make use of VSM to change the styling implementation.

One problem…the ToggleButton no longer supports MouseOver states specifically for Checked/Unchecked as we’ve implemented in the video player.  My first thought (and a few emails to the team) was to inherit from the ToggleButton and do my own implementation, adding those states into the control.  I was able to do this by creating a new class file in my Silverlight project, then inheriting from ToggleButton and a few overrides.  I first wanted to support VSM so I added the appropriate TemplateParts to my class:

[TemplateVisualState(Name = "CheckedMouseOver", GroupName = "CheckStates"), 
TemplateVisualState(Name = "CheckedMouseOut", GroupName = "CheckStates"), TemplateVisualState(Name = "UncheckedMouseOver", GroupName = "CheckStates"),
TemplateVisualState(Name = "UncheckedMouseOut", GroupName = "CheckStates")] public class ToggleButtonEnhanced : ToggleButton {

This worked fine and they showed up in Blend designers as well for me to implement.  I then chose to override the MouseEnter/Leave events and did something quick like this:

protected override void OnMouseEnter(MouseEventArgs e)
{
    base.OnMouseEnter(e);
    if (base.IsEnabled)
    {
        if ((bool)base.IsChecked)
        {
            VisualStateManager.GoToState(this, "CheckedMouseOver", true);
        }
        else if ((bool)!base.IsChecked)
        {
            VisualStateManager.GoToState(this, "UncheckedMouseOver", true);
        }
    }
}

Fair enough right?  Well it appeared to be working.  The problem was that ToggleButton maintained a Normal state that was conflicting with certain scenarios I had in my implementation.  You see the base.OnMouseEnter() was essentially the rathole here.  Some spelunking showed that when a state changed it actualy went from the desired state, then back to ‘Normal’ – for example the Pressed action wend: MouseOver,Pressed,Normal.  The final transition was causing my problem.

Now I was looking at overriding the OnApplyTemplate method and thus virtually having to re-implement all the other state transitions as well.  Now I’m no longer really getting a huge benefit out of my inheritance.  So I went back to some experts for some advice.  Dave gave me some pointers and we chatted about the implementation and desired outcomes.  Dave’s much smarter than me on VSM, well, because he had to implement it :-).  For my particular scenario he pointed out that I really had only one property that was changing in the MouseEnter/Leave events: Opacity.  So why not just change Opacity for the Grid container rather than worry about the elements.  Duh.

So now I no longer needed my custom ToggleButton, but could use the primitive ToggleButton to do my dirty work.  I implemented the MouseOver, Checked, and Unchecked states is all I really needed to manage my transitions.  A few learnings about some things I was doing wrong and boom, the new player works as expected.

I learned a few things in this quick journey through VSMville, and one was that it was pretty easy to implement a custom control to support the VisualStateManager model as well.  I think I’ll be digging into this one deeper soon.

Hope this helps someone!  Here’s the code for the updated Video Player.  While the ToggleButtonEnhanced is not used in the final implementation, I kept it in the code file so you could see what path I started along.

| Comments

Um.  Whoa.

Okay, DevExpress rocks.  I think this will be very well received by the community and you’ll have to watch their page for when it is available and to get your license.

From their site:

As the release of Silverlight draws near, DevExpress has invested the engineering resources needed to deliver a feature-rich grid control for Silverlight. Not just a "preview" of what is possible with Silverlight, the AgDataGrid Suite was developed to fully exploit the power and flexibility of the platform…

It looks like it will support pretty much everything you’d expect in a DataGrid and more…wicked cool.  Congratulations and thank you to DevExpress!!!

| Comments

Silverlight 2 brings a suite of controls for designers and developers to leverage within their applications.  With the Expression tools helping us to be able to skin these controls, also comes some new controls you may not have used yet as well as a new one introduced with the latest release of Silverlight 2.

Introducing TabControl.

UPDATE: Video walk-through is now live.

The TabControl is implemented in the System.Windows.Controls.Extended class library and not in the Silverlight core.  To use it make a reference to the Extended assembly and it will be available to you.  In Expression Blend you’ll see TabControl in the Custom Controls section of the Asset Library:

You’ll notice there is actually a TabControl and TabItem controls…to implement you’ll need them both.  In Blend, you’ll have to drag a TabControl onto the design surface.  Once you have it, double-click on the TabControl in the Objects and Timeline explorer so that it has a yellow ring around it:

Having the yellow border indicates that it is the actively selected element.  Now if you go back to the asset library, change to a TabItem and double-click the TabItem, it will be added as a child of the TabControl.  Do this several times to add as many TabItems you need:

The resulting XAML looks like this:

<ex:TabControl TabStripPlacement="Bottom" VerticalAlignment="Top" 
               Width="231.148" Height="156.611" HorizontalAlignment="Left" 
               x:Name="tabstrip1">
    <ex:TabItem Width="75" Height="20">
    </ex:TabItem>
    <ex:TabItem Width="75" Height="20" Header="Second">
    </ex:TabItem>
    <ex:TabItem Width="75" Height="20" Header="Third">
    </ex:TabItem>
</ex:TabControl>

You’ll notice the “ex” namespace with the TabControl.  Yours may be different and likely “System_Windows_Controls“ if you followed the steps above.  This is added automatically when you drag a control onto the surface from the asset library.  The namespace is actually directed in the root node of the XAML and you can change it to whatever you’d like.

The TabControl has properties you can set on it just like any other control, but one that you might find important would be the TabStripPlacement property.  This enables you to direct where the TabItems (tabs) actually get displayed: Top, Left, Right, or Bottom.  This can be set in XAML and also controlled during runtime using the Dock enumeration.

Each TabItem also has two properties to set content: Header and Content.  Header is where you would put the content for the tab itself and content direct the actual content within the TabItem.  This can be set to literal string values, but they can also be set to other content.  For example, if you want to set the content within the TabItem, you could do something like:

<ex:TabItem Width="75" Height="20" Header="Third">
    <StackPanel Orientation="Vertical">
        <TextBox x:Name="yourname" />
        <Button Content="Click me" Click="Button_Click" />
        <TextBlock x:Name="resulttext" />
    </StackPanel>
</ex:TabItem>

If you wanted to set alternate content as the Header you could likewise do that as well noting the TabItem.Header:

<ex:TabItem Width="75" Height="20">
    <ex:TabItem.Header>
        <Button Content="foo" />
    </ex:TabItem.Header>
    <Button Content="Click Me" Click="Button_Click_1"/>
</ex:TabItem>

Let us all welcome TabControl to the family.  A simple yet probably widely used control is now available for you to think of marvelous uses :-).  Remember, that TabControl (as well as the calendar and date picker controls) is located in the Extended control assembly and not the core.  Here’s an example of a TabControl using some of the methods described above:

For a video demonstration of using TabControl, visit the Silverlight community learning section and stay updated as the video will be there shortly as well as other great videos on using Silverlight 2.

Hope this helps!

| Comments

This has been one of the features that I’ve been excited about for a while since I heard we were changing it.  With the release of Silverlight 2 Beta 2 and the updated preview of Expression Blend 2.5 (June 2008), skinning and styling controls within Silverlight gets a bunch easier.

Sample skins from Corrina Barber

When Silverlight 2 Beta 1 was released there was the possibility of styling/skinning controls.  It wasn’t impossible, but perhaps a bit obfuscated to the eye for people with short attention spans like myself.  You can read more about those methods here and here.  WPF designers were probably laughing that Silverlight developers might have been struggling with skinning controls.  Why?  Because Blend for WPF supports a right-click “Edit Template” functionality for WPF…so where is it for Silverlight?  In the latest release of Blend 2.5 of course!

That’s right—simpler skinning.  At RIApalooza in fact I was asked about how one would know *what* elements could be skinned, etc.  Outside of the docs, and some spelunking, it wasn’t entirely intuitive.  But now, well, let’s take a look.  Let’s take a look at Blend 2.5 June 2008 preview and adding a ScrollBar to our design surface:

You may not realize it but the ScrollBar has a lot of elements that you can skin.  The thumb, the handles, the bar, every little detail…so now in Blend 2.5 we can right-click and choose to edit that:

When you do this you are prompted for some settings, one to name the style and the second of where to put it, either in the document resources or as an application resource that other controls may subscribe to:

After you do this, your objects and timelines explorer (on the left by default unless you’ve moved it) now changes to represent the layered elements of the control you are skinning now.  Note that the “up” arrow will get you out of this mode and back to your documents visual tree of elements.  Here’s what the base template for ScrollBar looks like:

You can continue to dig further.  For example with ScrollBar, if you wanted to modify the Thumb, simply select that in the visual object tree:

then right-click on the Thumb now on the design surface and choose to edit that template and now you’ll see that you can edit the Thumb’s template rather simply:

If I wanted to I can remove the three elements that make up the HortizontalThumb and make my Thumb an Image of myself (horrible design, but proving a point):

I chose ScrollBar in this post, but you can do this with any of the controls and the process is the same.  This now makes skinning a bit more within a closer reach to most.  The reach for developers might be a bit further if you have no design skills…but I’ll gladly send you my picture if you want to use it as your navigational Thumb for ScrollBar.

One other tip is that when you have an element on the design surface that has a template skin attached to it, Blend will help you get there even faster rather than having to right-click further.  At the top there is a breadcrumb like trail and if you are on an element that has a template there will be a “Template” link you can click directly on:

Hope this helps!

| Comments

While Silverlight 2 brings us great capabilities as .NET developers and opens many opportunities for creating rich clients in the browser, it still supports strong media features that have been available since the initial release of Silverlight.  The ability to deliver efficient, high quality media in the browser is an increasing need in a lot of sites producing content for their members.  Traditional ‘podcasts’ which were historically audio-only, are moving increasingly faster to richer media.  This is nothing new of course, but being able to quickly distribute the media on your sites efficiently and provide methods for your users to either embed content, or for you to deliver content to other sites means you need a predictable method for doing that.

In Silverlight 1, while it supported all the same features, one thing that I (and presumably you as well) didn’t find attractive was the deployment scenarios for delivering media content via players.  Silverlight 1 required the distribution of various scripts and initialization functions.  This wasn’t ideal for providing you with something you can just drop into a web page anywhere.  In fact, it was preventative in some places like MySpace, for example.

Silverlight 2 brings a new packaging model, the XAP (pronounced “zap”) file.  Essentially this is an archive file which contains a manifest, reference assemblies and any custom code you have created.  It can also contain resources that your application may use.  Because we have this format now, we aren’t restricted to delivering multiple files for our application…we can deliver our application in one file essentially (your mileage may vary depending on your needs).

Great, now we have a good packaging model, but what about drawing my own controls, etc.?

True, Silverlight 1 had a gap of native controls to the runtime, requiring you to be creative with XAML to deliver functionality.  In the typical media player scenario where you want a few timelines, volume bar, etc…even the trivial tasks required you to wire up some functionality.  Well, Silverlight 2 brings us a common set of controls now that we can leverage.

So let’s take a look at an implementation of a Silverlight 2 media player.  I’m going to use a base player created by Joel Neubeck who has been doing some really great posting on Silverlight lately.  In this example I’m going to try to articulate what Joel did with the base controls and demonstrate how he was able to create an effective use of styling and controls to create a re-usable player.  Additionally, I’m going to add a few new features to it for my desires.

I’m not going to go into the full details of this code, but wanted to point out the key features of what Joel accomplished as I think it was clever use of some controls you might not have considered to use in this scenario.  As well, I’ll show what I added and why.

The Controls

We’ll need a play/pause button, a track timeline, perhaps a download timeline, volume controls, and full-screen button.  We could do these in various ways.  For our buttons we could create canvas elements and add a lot of code to switch them on/off.  We could use a regular button and hide/show different ones.  I thought Joel made an excellent choice in choosing to use a ToggleButton.  The ToggleButton is still a button with all the same features, but supports more than just a normal/pressed state.  Essentially it supports a ‘checked’ state similar to a checkbox or something.  This is useful because we’re using this to basically provide play and pause capabilities.  By using a ToggleButton, we can essentially make the ‘normal’ state the Play view and the pressed (checked) state the Pause view. 

Okay, now for the tracks.  In Silverlight 1 we would have to use a few rectangles on top of each other, add our mouse capture code, etc.  In Silverlight 2, Joel saw the Slider as being an effective way of showing a linear timeline and it provides the functionality for value changing and a thumb for scrubbing, etc.  Perfect.  We’ll use the Slider for the download and volume features as well.

So once we add these to our design surface (Joel chose to create the media controls as a separate UserControl) it looks like this:

Skinning the Controls

Blah.  That looks like crap and rather button-sh.  Here is where skinning comes in.  Jesse just completed a good tutorial on skinning controls that provide a little more depth.  Using this techniques, we can define at a more granular level what we want our content views to be.  For example on the play/pause button, instead of a ‘button’, we replace the content with Path elements that are geometric shapes rather than a typical button look.  In combination now with implementing states in the styles (i.e., Normal State, Pressed State, Checked State) we can define that when the button is pressed (checked) what it shall do/look like by pre-defining the state.

We apply these same concepts to our other controls like the slider, able to skin the timeline area independent from the thumb scrubber, etc.  We put our styles in App.xaml so they are globally available to the application.  Do this with the volume control and other buttons (mute/full-screen) and now our exact same media controls (without affecting any real code that controls the logic), we now have this look:

which looks much more like what we are after. 

Now Joel’s initial example was fixed to a specific size of a media file.  I want my player to scale to whatever the container is.  Essentially I removed all specific sizes from XAML where appropriate and changed the media controls container grid so that the center column (where the timeline sliders are) will expand/contract as needed.  This gives us two features.  The first is that we have a re-usable control area regardless of the media element size.  The second is that when the user goes into full screen mode, the controls also expand to full screen appropriately.  The only thing you have to do is set the containing <div> where this media player is going to live to the desired size (i.e., 640x480) and the application will scale the internal elements to fill that space accordingly.  Full screen mode will as well adjust the controls to fill the screen.

I also added a bigger “Play” indicator (and buffering indicator) that would show in the center of the MediaElement when paused or buffering.  I felt this gave more visual cueing to what was going on with the media.  This also scales as it looks at the ActualWidth/Height properties and grabs the center points based on that.  Here’s the resulting paused view in two different sizes:

640x480 view

320x240 view

Providing Startup Parameters

The next thing I wanted to do is eliminate the hard-coding of the MediaElement Source property in the base XAML file.  I just created a player with all my needs and want to re-use it without recompiling, etc.  Here’s where InitParams comes in for developers.  One thing we can do to the plugin is pass startup parameters to it.  These are surfaced using the InitParams functionality.  You can specify a comma-delimited list of name/value pairs in this property like:

firstName=Tim,lastName=Heuer,loves=Silverlight

which in turn get put into a Dictionary object in code.  These elements are retrievable in your applications Application_Startup in the StartupEventArgs.  the Application_Startup is in the App.xaml file (you can think of this as a global.asax file if you are an ASP.NET developer).  There are different ways you can implement grabbing these values out.  You could pull values (or just one value) out using a simple retrieval of the key value:

string firstName = e.InitParams[“firstName”].ToString();

You could set this to a public static variable that could then be accessed by your application.  I chose to simply iterate through the initialization parameters and add them to the resources collection of the application.  I haven’t decided yet if this is the most effective use, but for now it works and was simple:

foreach (var item in e.InitParams)
{
    if (item.Key.ToLower() == "m")
    {
        string mediaParam = e.InitParams["m"].ToString();
        Uri mediaUri;

        if (mediaParam.Contains("://"))
        {
            mediaUri = new Uri(mediaParam, UriKind.RelativeOrAbsolute);
        }
        else
        {
            mediaUri = new Uri(mediaParam, UriKind.Relative);
        }

        this.Resources.Add("m", mediaUri);
    }
    else
    {
        this.Resources.Add(item.Key, item.Value);
    }
}

You’ll see that i check for an “m” parameter and do an additional checking on that.  I’m using this parameter for passing in the source for the MediaElement and need to check if it is an absolute URI or if the media will be local to the Silverlight application.  Then any other initialization params get added to the collection as well.  This might not make sense because I’m really only using two: source and autostart and if I wanted to make this re-usable, I would really need to build up more options and put them in the code too, or else nothing is being used.  I’ll likely do that later, so let’s move on.

Now that we have these items in our Resources collection, my app continues to load and set the MediaElement source to that value:

mediaPlayer.Source = App.Current.Resources["m"] as Uri;

As a // TODO I need to add some error checking and display the thumbnail if there is a problem perhaps, but I’ll get to that later.  Anything else I might need to do with the startup params I can get them out using the same method as above now that they are in my Resources collection.

So now in my control hosted page I have this:

<div style="width:640px;height:480px">
    <asp:Silverlight ID="Xaml1" runat="server" 
    InitParameters="m=LEADER_ST2.wmv,autostart=false" 
    Source="~/ClientBin/VideoPlayer.xap" Version="2.0" 
    Width="100%" Height="100%" />
</div>

Here I was using the asp:silverlight control which exposes the InitParameters property, but I could use the object tag directly:

<object data="data:application/x-silverlight," type="application/x-silverlight-2-b1" 
        width="640" height="480">
    <param name="source" value="ClientBin/VideoPlayer.xap"/>
    <param name="onerror" value="onSilverlightError" />
    <param name="background" value="white" />
    <param name="initParams" value="m=LEADER_ST2.wmv" />
</object>

NOTE: In the “m” parameter it will use the standard path resolution that Silverlight respects.  For more information on this, see a great post by Pete Brown on the explanation.

Providing Alternate Content

As you can see we have provided no alternate content for the object tag implementation.  The asp:silverlight control also supports providing alternate content via the PluginNotInstalledTemplate property.  This is the responsibility of the web developer implementing any active content, whether it be Silverlight, Flash or other embeddable technology.  For more information on methods of doing this, read my blog post regarding a great deployment experience.

Summary

Now I have a media player that expands to the size it needs as well as is totally re-usable for me as I can provide startup parameters to it providing the media to play.  There is some polish that probably needs to occur, but as you can see, by using the native controls we get a lot of free functionality that we can tap into and by skinning the controls you get a much better look than the default and can even totally change the visual behavior of native controls.  Thanks to Joel for his great work using native controls and state parts and skins to create a great media player.  I’ve only made a few tweaks that I think were value add, but download the code and see what you can make with it. – all you need to do is change the styles and let’s see what you come up with!

Here’s the source as it is right now with my modifications to Joel’s existing work: VideoPlayer.zip.

UPDATE: Updated code using VisualStateManager and beta 2 styling method is here.