| Comments

This is part 6 in a series on getting started with Silverlight.  To view the index to the series click here. You can download the completed project files for this sample application in C# or Visual Basic.

We now have a functioning application but could use some more polish.  Let’s make the data template for the search results look a little better.  We’re going to modify a few things in the data template in Search.xaml for the ItemsControl. 

These modifications can be done in Blend just like we have been doing with the editing template features.  This is how it was accomplished above.  With these styles now applied the new UI looks like this:

Styled results

Notice how more polished that looks and we didn’t affect any code, just the template style.  Since there was a few changes here since the last step it would be a lot of code to write out but let me point out where the styles are in the final project.

The styles and templates are applied just like the binding syntax with data and the templates.  If we look at the ScrollViewer it now states:

   1: <ScrollViewer Style="{StaticResource scrollViewerStyle}" ...
   2: ...

Notice the familiar syntax?  instead of {Binding} it uses {StaticResource} to refer to a resource that either exists in the document or the App.xaml.  In this case the style is in the App.xaml (look for the scrollViewerStyle and scrollBarStyle nodes at the bottom of the file).

We also just made some subtle changes to the colors of the included style from the template.  With styling and templating in Blend, you don’t have to worry about modifying your .NET code most of the time.  We are able to change the visual layout and theme of controls without changing the code.

More resources on using Expression Blend:

Having a designer friend at this stage of polishing the UI is extremely helpful.  In fact, you’d likely have this UI defined MUCH earlier in the project than our exercise here.  The two tools, Expression Blend and Visual Studio, share the same project structure file so you can easily open the project in either tool instead of passing around loose files.

Take a look around the Assets/Styles.xaml file in the completed project to understand how styles and templates can be used.

Next step: finishing off our application by making it available out-of-browser in part 7.

| Comments

If you’ve heard the news about Silverlight 2 Beta 2 and Expression Blend 2.5 (June 2008 preview), you will notice something else in addition to being able to skin your controls easier.  Remember how you may have had to create different states for your element using “MouseOver State" and then create storyboards to transition to states?  There’s now a better way.

Enter VisualStateManager.

Let’s take a look and see if we can simplify this down a bit a basic understanding.  Let’s use something that most everyone should be able to relate to with states: Button.  A button has MouseOver, MouseOut, MouseDown, etc. states that you can see.  Using VisualStateManager and the new UI ability to customize templates, we can make our lives easier.

Start in Expression Blend and drop a button on the default design surface.  I’ve created mine larger just for context, but whatever you want is fine.  You should have something like this:

Now, using the method in one of my previous posts about skinning the controls, right-click on the button and choose to edit the template.  I’d choose Edit a Copy for now to make things easier for now…keep it a document resource as well.  After you’ve done that, take a look in the upper left pallette (assuming default and you haven’t moved your palettes around…in which case you probably already know about VSM and are smarter than me anyway):

The various states of this control are represented in this particular template.  Some other controls might have a blank palette here until some are added, but Button has some default states.  As a designer now you can simply concentrate on what the final look of the element (in our case a Button) in each state.  Just define the state and what the element should look like in that state.  The State palette shows a few things.  You’ll notice “Base” as well as two other named containers, “CommonStates” and “FocusStates” which are what are called state groups and containers for different states.

Beneath that you can select a state and see it’s final state.  Want to change the MouseOver state, select it in the state palette and start customizing the template.  Let’s change the MouseOver state, select it and let’s change some properties.  By default it looks like this:

You’ll also notice a few things changed.  Basically the design surface goes into Timeline recording mode and a subtle new feature in the objects palette indicating the property being animated/changed…in this case the BackgroundGradient:

I’m selecting the BackgroundGradient element and then changing the color within the Properties palette.  Let’s change it to red.  There is no need for me to pay attention to any timeline stop points or anything, just concentrate on what I want the final Button to look like, position, etc. in this state:

That’s it.  MouseOver will now represent my new state.  I didn’t have to create any new StoryBoard elements or anything.  This is in part where VSM does some magic.  You see, the VSM engine bascially knows the beginning end states between any given transition (i.e., Normal –> MouseOver).  The VSM engine automatically handles the transition for us.  Think of it as creating a dynamic StoryBoard on the fly and executing it.  If we run the application and mouse over the Button, it changes to our state.

Notice the time in the state palette for a given state:

This controls the duration of the transition TO that final state.

The VSM model also enables you to move between states via code.  VisualStateManager.GoToState() is a static method that enables you to move between states and optionally use the transition or just get to the state.  For example if we had our Button named "foo" and had some other event we could do this:

VisualStateManager.GoToState(foo, "MouseOver", true);

The last parameter is to use the transition or not.  True would do the transition based on the duration set in that state.  False just gets to that state.

The theory is that VisualStateManager now makes it easy for us with our skinning, etc., but also separates more from the developer/designer so that the designer can concentrate on the final look and experience of the final states rather than having to code something up.

A Button used above is a simple example and I hope it helps demonstrate the VSM class available.  There could be other uses than the simple Button of course :-) and I hope to see some creative uses.  As a for instance, I've seen a lot of applications with slide-out control panel implementations.  You could use VisualStateManager and set the "collapsed" and "open" states for a control panel and just concentrate on the final stages of each and let VSM handle the transitions, etc. 

For some further designer-driven tutorials on this model, head on over to Nibbles where Celso will have some tutorials on what VSM means to designers in more depth.  Also be sure to check out Christian’s blog for more information on VisualStateManager.

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.