Saw some posts today over at Don’s site about Surface.  The Surface SDK is starting to get more visible whereas before it seemed a little black-boxish to me.  Turns out (as we all knew) it really is just WPF with some unique Surface-like behaviors in the SDK.  Take this quick demonstration from a program manager on the SDK.  With using the same concepts that we use in WPF and Silverlight for data binding, etc. you can come up with a quick application using the inherent gesture support from a Surface device:

Pretty cool huh?  Same XAML concepts we apply in current work today, but instead of StackPanel, you add a ScatterView and boom, you get some of that simiplistic gesturing support.  Now I know we aren’t all running out to create a photo album viewer to stretch photos, but it’s a good demonstration of some of the simplicity in the SDK.  I kinda wish the ScatterView was actually a Silverlight control :-)

Regardless of your views on politics, here’s an implementation of Surface that MSNBC is starting to use in their newsroom.  I think this is a great use of the device and SDK…it shows a great use-case scenario (and the guy seems to be having fun with it)

Anyhow, I thought these were some great examples of the SDK and a non-entertainment/media) app in use.

So you want H.264 support in Silverlight?  So do we.  In fact we will be showing a preview of H.264 and AAC support in Silverlight at the International Broadcasting Conference (IBC) this week in Amsterdam.  Scott Guthrie comments on this saying:

At IBC 2008 we will be demonstrating a technology preview of H.264 video and Advanced Audio Coding (AAC) audio playback support in Silverlight, and H.264 authoring using Microsoft Expression Encoder and Windows Server 2008 for delivery. Until now, Silverlight has supported the SMPTE VC-1 and Windows Media formats, as well as MP3 for audio, enabling customers to take advantage of broad support across the Windows Media ecosystem, including third-party tools, service providers and content delivery networks.

We’ve always wanted Silverlight to support a variety of formats, so today we’re announcing that H.264 and AAC support will be available in a future version of Silverlight, which will offer content owners greater flexibility and choice to deliver video and audio.”

One thing that I didn’t know was that Microsoft has been an active member in the standardization of H.264.  Microsoft’s Gary Sullivan was the chairman of the Joint Video Team (JVT) which developed the H.264 standard.

This is exciting news for the future of Silverlight.  I hope that this is good news to the implementers of media and Silverlight.  You can find out more information about the IBC here and a full Q&A with ScottGu here which also gives some great information about the results of viewing at NBCOlympics.com and where other uses of Windows Media Server were implemented (CCTV for example).

UPDATE: To clarify, this support will be in a future version of Silverlight.


This work is licensed under a Creative Commons Attribution By license.

Man, I feel like I’m constantly on this soapbox about creating a good non-installed experience.  I’m recently sparked again by reading a recent post from Pascal Leloup entitled “Silverlight – It’s too damn complicated to setup.”  These are the times that I wish I could sit next to every developer at the moment they experience this frustration.

Part of the time it can be dealing with beta software (as is the case in one of Pascal’s scenarios here), and others I think just take some time to understand the why behind certain things.  Let me take a stab at some things here for Pascal’s (and hopefully yours too) benefit.  While his specific example was around a media player, some of these concepts go far beyond that.

ASP.NET Media Control

If you use the ASP.NET Media Control (<asp:MediaPlayer/>) you get some ease of being able to just drop it in, attach a media source (WMV/WMA/MP3) and you get a player.  One thing to note though is that the output is a Silverlight 1.0 application, not a Silveright 2 experience.  The scripts and templates for the ASP.NET Media Control are embedded resources.  You can certainly supply your own skin, but have to create it.  The documentation for the control are available here where you can see how it can be used, how you can use Javascript to program against it, and how you can use various MediaSkin files or create your own.  In my honest opinion, this is a good start, but will not likely get you to a customized user experience for the media playback experience.  Additionally, you can customize the ‘not installed’ experience as it exposes the PluginNotInstalledTemplate property that you can put whatever you want there.

Pascal says:

“…they have to make sure the Media player ASP.Net user control continue to be updated or maybe put it back to the Ajax Control Toolkit as an open source project, to be sure the community can improve it.”

I will be honest and say I’m not sure if the skin thing with using Javascript will be changing by Silverlight 2 timeframe…but the necessary scripts, etc. are continually being updated.  As I’ve said (sorry ASP.NET team), I think if you are looking for a highly customized experience, this may not be the control for you.

Silverlight.js

I’m assuming that Pascal probably is a Firefox user and the initial use of the script was continuing to show the install badge logo.  Based on the comments, it sounds like really outdated tools.  The script available on MSDN (which is the latest) has the proper install links and also fixes the problem with Firefox 3 detection.

Keep in mind though this is just a script.  It isn’t going to automatically do everything for you.  It should be considered an SDK tool and help you do some detection and provide alternate content to the user if the plugin is not installed.

Silverlight control

I assume here Pascal means the <object> tag and thus a Silverlight 2 application.  It looks like for the most part he got this working (with some media problems that I’m happy to try to resolve; oh and Pascal the media stretch fix has been checked in to the Codeplex project).  As to the Firefox 3 ‘official’ support…Silverlight 2 is still in beta and we’ve already said that we’ll be supporting Firefox 3.

Pascal comments:

“The other matter is to get a much cleaner way to implement easily Silverlight 2 on an ASPX page. Why not doing something like the Listview, with a template part where we can put our own installation links?”

Actually you can.  There are two ways you can do this, but let me show you a snippet, first using the ASP:Silverlight control:

   1: <asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/_SilverlightApplication1.xap" 
   2:         MinimumVersion="2.0.30523" Width="100%" Height="100%">
   3:     <PluginNotInstalledTemplate>
   4:         <a href="http://go.microsoft.com/fwlink/?LinkID=115261" style="text-decoration: none;">
   5:             <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
   6:         </a>
   7:     </PluginNotInstalledTemplate>
   8: </asp:Silverlight>

Which essentially would be the same as:

   1: <object data="data:application/x-silverlight," type="application/x-silverlight-2-b2" 
   2:     width="100%" height="100%">
   3:     <param name="source" value="ClientBin/_SilverlightApplication1.xap"/>
   4:     <a href="http://go.microsoft.com/fwlink/?LinkID=115261" style="text-decoration: none;">
   5:         <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
   6:     </a>
   7: </object>

So you can see that ASP.NET does provide a method for putting Silverlight applications there using the ASP:Silverlight control and also exposes the PluginNotInstalledTemplate object for you to customize.  In the non-ASP.NET example, you can see that the alternate content is provided after the last <param> tag in the <object> tag.  What will happen here is that if the <object> tag is not understood, it will render the HTML it can understand.  You can see more about this on this screencast.

“Big Huge Icon”

Pascal notes:

“They automatically put a big huge icon in your face without any explanation at all to tell your grandmother what the hell to do with this bluish Silverlight logo? Super.. what?  I’d loved to add my own touch, an help button, a new logo, no hope.”

On the last sentence of no hope to add your own touch, he couldn’t be further from the truth…more on that in a second.

On the first note: I couldn’t agree more!  I get frustrated when I see the Get Microsoft Silverlight install badge.  But the challenge is that it is the best default for people who aren’t customizing their experience.  We could have come up with a super creative, very descriptive image, but what if the Silverlight content is only 10x10px?  As it stands now, the default image wouldn’t look good in that scenario!

The point here is that the developer must own the install experience.  Silverlight isn’t on every desktop, let’s be honest.  The focus in the ‘not installed’ experience should be your content/company and not Silverlight.  It is important to keep the Silverlight branding at some level because once they click install it will show them the Silverlight installer and you want to keep continuity in the message of what they are installing.  Outside of that though, you own that space.  Maybe I should lobby to change the Visual Studio templates to add comment code instead of the default badge so that it reads:

   1: <!-- PUT YOUR CUSTOM PLUGIN NOT INSTALLED EXPERIENCE HERE -->

I’ve already written about some good examples of doing this.  It was even pointed out in the video player Codeplex project that I participate in, that we didn’t have guidance on that.  I cringed a little bit to even provide a sample, because I really believe the web site should own that experience…but I at least put a sample in the documentation.

When Silverlight ships we’ll be providing an updated installation guidance document talking about the various ways you can do this, with some clear samples of the SDK methods of detection of upgrades, non-installs, browser refresh/restarting, etc.  The one thing the document won’t do, however, and that is provide you that alternate HTML.  Why?  Because the non-installed experience is about your content, not Silverlight.  Imagine how you feel now when you see the “big huge icon” – it doesn’t make sense right?  Neither will it to your customers if you don’t provide them with information.  And don’t ask Microsoft to provide the samples…why would you want Microsoft to design/describe the content from your organization?

Summary

Sorry to keep repeating, but it’s about the content, not Silverlight.  Content is king.  If you are looking for a gallery of ‘not installed’ template experiences, stop looking – it doesn’t make sense.  Your brand in your application/site/organization is important and won’t be found in any templates.  Even other rich platforms don’t provide custom templates.

Be sure to take time to add this as a work item to your projects using Silverlight…don’t forget about it.  This is an important step in early adoption of your content in Silverlight and you should take time to nail that experience.  As I mentioned, we’ll provide updated guidance on any new settings/APIs that you can tap into to make the most out of that experience and minimize the impact to your end-user.

Related Resources:

In NYC this weekend and want to hang out and learn some Silverlight?  Some community leaders and Microsoft folk are putting on a Silverlight 2 Firestarter event this weekend on 13-SEP.  Shawn Wildermuth of the Silverlight Tour will be there for the keynote and giving some sessions as well.  It looks like some folks from Infragistics will be there as well…I’d imagine they might have some cool things to talk about!

The event is free for anyone to attend and should be a good time hanging out with fellow geeks in NYC and learning what others are doing with Silverlight 2!  Registration will probably fill up quick!

If you use the Slider object in Silverlight (or WPF for that matter) you may have experienced some similar frustration that I have recently.  Let’s take a look at what the Slider is first.

The Slider is a simple control on the surface providing a track and a “thumb” (if you aren’t familiar with that term) that enables value changing.  Some of the key properties are:

    • Minimum – the number that represents the lowest (left or bottom) value
    • Maximum – the number that represents the highest (right or top) value
    • LargeChange – the slip when a large change in value is desired
    • SmallChange – the slip when a small change in value is desired

It is the last two properties that caused me some headache.  To understand, let me try to explain the functionality first.  Looking at the image above, you’ll see that the track is a certain length.  In my setting I have Minimum set to 1 and Maximum set to 100 above.  Therefore the current Thumb position (Value) is about 20.  Notice where the mouse cursor is?  If I were to actually click there here is what the result would be:

What?!  You may be asking yourself the same thing.  Why didn’t the Thumb move to the curser clicked position?  How did it determine where to move?  Enter the Small/Large change values.  In my setting I have LargeChange set to 10.  What is happening is when I visually click on position at about 80, the Slider sees a large change occurring and moves one LargeChange value.  If I would have clicked close to the Thumb, SmallChange would have happened as well.  This is quite annoying when your users will probably expect that clicking on the track will take them to that point.

Incidentally, the WPF Slider has a property called IsMoveToPointEnabled which turns this functionality on.  This property is not available in the Silverlight Slider (as of Beta 2).

So what if you need that functionality?  Well, here’s one way (with a hat not to my colleague John Lemire for turning me on to this method).  This does involve some code and modifying the template, but it isn’t that painful at all.

Modify the Template

Using Expression Blend, we can modify what the template definition of a Slider is.  To do this, open up the project in Blend, select the Slider object, right-click and choose Edit Control Parts (Template)…Edit a Copy.  Give it a name (I named mine CustomSlider and kept it as a document resource as opposed to an Appliction one).  You’ll then see that you can now edit the template.  There is actually a template for Horizontal and Vertical (Slider has an orientation property), but let’s just concentrate on Horizontal.  The template is made up of: Rectangle, 2 RepeatButtons and a Thumb.  Make sure the Thumb is named “HorizontalThumb” as we’ll need to refer to it later.  Now let’s add some Rectangles.

We’re going to add Rectangles “on top” of the RepeatButtons in use.  You see, when you click on the track in Slider, you’re actually clicking on the RepeatButton areas.  So right now our default template should look like this (for the HorizontalTemplate area only):

   1: <Grid x:Name="HorizontalTemplate">
   2:     <Grid.ColumnDefinitions>
   3:         <ColumnDefinition Width="Auto"/>
   4:         <ColumnDefinition Width="Auto"/>
   5:         <ColumnDefinition Width="*"/>
   6:     </Grid.ColumnDefinitions>
   7:     <Rectangle Height="3" Margin="5,0,5,0" Grid.Column="0" Grid.ColumnSpan="3" Fill="#FFE6EFF7" Stroke="Black" StrokeThickness="0.5"/>
   8:     <RepeatButton IsTabStop="False" Template="{StaticResource RepeatButtonTemplate}" x:Name="HorizontalTrackLargeChangeDecreaseRepeatButton" Grid.Column="0"/>
   9:     <Thumb Height="18" x:Name="HorizontalThumb" Width="11" Grid.Column="1"/>
  10:     <RepeatButton IsTabStop="False" Template="{StaticResource RepeatButtonTemplate}" x:Name="HorizontalTrackLargeChangeIncreaseRepeatButton" Grid.Column="2"/>
  11: </Grid>

We’re now going to add 2 Rectangles, one after the left RepeatButton and one after the right RepeatButton, named LeftTrack and RightTrack respectively.  You can do this in the XAML code or just drag the Rectangles on the design surface in Blend and arrange accordingly.  The result should be this:

   1: <Grid x:Name="HorizontalTemplate">
   2:     <Grid.ColumnDefinitions>
   3:         <ColumnDefinition Width="Auto"/>
   4:         <ColumnDefinition Width="Auto"/>
   5:         <ColumnDefinition Width="*"/>
   6:     </Grid.ColumnDefinitions>
   7:     <Rectangle Height="3" Margin="5,0,5,0" Grid.Column="0" Grid.ColumnSpan="3" Fill="#FFE6EFF7" Stroke="Black" StrokeThickness="0.5"/>
   8:     <RepeatButton IsTabStop="False" Template="{StaticResource RepeatButtonTemplate}" x:Name="HorizontalTrackLargeChangeDecreaseRepeatButton" Grid.Column="0"/>
   9:     <Rectangle x:Name="LeftTrack" Grid.Row="1" Fill="#00FFFFFF" Cursor="Hand"/>
  10:     <Thumb Height="18" x:Name="HorizontalThumb" Width="11" Grid.Column="1"/>
  11:     <RepeatButton IsTabStop="False" Template="{StaticResource RepeatButtonTemplate}" x:Name="HorizontalTrackLargeChangeIncreaseRepeatButton" Grid.Column="2"/>
  12:     <Rectangle x:Name="RightTrack" Grid.Column="2" Grid.Row="1" Fill="#00FFFFFF" Cursor="Hand"/>
  13: </Grid>

Visually you won’t be able to notice any difference because we added Rectangle elements that are have 0% opacity, so the Slider still looks the same.

Create Custom Slider Code

Ok, now let’s move on to code.  I use Visual Studio 2008, so I’ll be referring to that.  In Blend, you can right-click on the project and choose to Edit in Visual Studio which will open the project in Visual Studio for you.  Once open in Visual Studio, add a new Class to your project, I called mine CustomSliderControl.  We’re going to inherit from Slider so we can implement all the same features, we are just augmenting one of them.

We will need a reference to the Thumb and the two Left/Right Track elements we just added, so we’re going to make those member variables we can refer to later.  We’re going to override one function: OnApplyTemplate.  The overriding of OnApplyTemplate is only to set our member variables to the elements we’ll use in the other functions as well as set event handlers on our Left/Right Track Rectangles we added to the template.  Since our elements exist in a ControlTemplate, rather than use something like FindName, we’re going to use GetTemplateChild and refer to the name (the x:Name) of the element.

We’re also implementing our own function OnMoveThumbToMouse, which will be attached to the MouseLeftButtonDown events on Left/Right Track.  This function basically gets the Point position of the event (the mouse click) and sets the Value of our Sider to that position (based on looking at where it is in relation to the other elements).  When it is all said and done, our CustomSliderControl code in complete should look like this:

   1: using System;
   2: using System.Net;
   3: using System.Windows;
   4: using System.Windows.Controls;
   5: using System.Windows.Documents;
   6: using System.Windows.Ink;
   7: using System.Windows.Input;
   8: using System.Windows.Media;
   9: using System.Windows.Media.Animation;
  10: using System.Windows.Shapes;
  11: using System.Windows.Controls.Primitives;
  12:  
  13: namespace CustomSlider_CS
  14: {
  15:     public class CustomSliderControl : Slider
  16:     {
  17:         private Thumb _HorizontalThumb;
  18:         private FrameworkElement left;
  19:         private FrameworkElement right;
  20:  
  21:         public CustomSliderControl() { }
  22:  
  23:         public override void OnApplyTemplate()
  24:         {
  25:             base.OnApplyTemplate();
  26:  
  27:             _HorizontalThumb = GetTemplateChild("HorizontalThumb") as Thumb;
  28:  
  29:             left = GetTemplateChild("LeftTrack") as FrameworkElement;
  30:             right = GetTemplateChild("RightTrack") as FrameworkElement;
  31:  
  32:             if (left != null) left.MouseLeftButtonDown += new MouseButtonEventHandler(OnMoveThumbToMouse);
  33:             if (right != null) right.MouseLeftButtonDown += new MouseButtonEventHandler(OnMoveThumbToMouse);
  34:         }
  35:  
  36:         private void OnMoveThumbToMouse(object sender, MouseButtonEventArgs e)
  37:         {
  38:             Point p = e.GetPosition(this);
  39:  
  40:             Value = (p.X - (_HorizontalThumb.ActualWidth / 2)) / (ActualWidth - _HorizontalThumb.ActualWidth) * Maximum;
  41:         }
  42:     }
  43: }

Using the Custom Control

Now that we have this custom Slider, let’s use it.  If we go back to our Page.xaml (or whatever XAML where you had the Slider control to begin with) we need to add a few things.  First at the top, we need to add our XAML namespace so we can use it.  For my sample code I used this (my UserControl decorations):

   1: <UserControl
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     x:Class="CustomSlider_CS.Page"
   5:     xmlns:my="clr-namespace:CustomSlider_CS"
   6:     Width="Auto" Height="Auto" 
   7:     xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows">

Notice the “xmlns:my” decoration that points to my CLR namespace for my project.  This will enable me to use this in my XAML later.  Now I can simply find where I used <Slider/> and change to <my:CustomSliderControl/> like this:

   1: <my:CustomSliderControl Cursor="Hand" HorizontalAlignment="Stretch" 
   2:                                 Margin="8,17,8,20.0499992370605" VerticalAlignment="Stretch" 
   3:                                 LargeChange="10" Maximum="100" SmallChange="1" Value="20" 
   4:                                 x:Name="MySlider" Style="{StaticResource CustomSlider}"/>

I don’t have to change anything else, nor do I have to change the Style attribute.  Since our custom control inherits from Slider, all the other types still apply.  You’ll notice that the style itself still has the TargetType=”Slider” attribution and this will work for our custom type because it is a derivative.  Here’s the result (using Silverlight Streaming): click here.

Summary

So as you can see we can extend some of the base controls rather easily.  I hope this didn’t sound too confusing because it really isn’t.  You can download the entire source here in C# or VB to see for yourself.  This particular extension may be helpful when using Slider as a media track representing the timeline for a particular media element.

I hope this helps!