| Comments

At PDC the WPF Tookit was made available which provides several new controls to WPF to help bring even more compatibility to the WPF and Silverlight story.  The new controls were the DatePicker, Calendar, DataGrid and the VisualStateManager concept to WPF.  Ribbon controls were also provided to the WPF Toolkit, but are not covered here.

With the introduction of this toolkit, developers now have a way to get some even more common XAML code-base between projects.

Let’s take a look at a very simple example of both UI and code sharing with WPF and Silverlight.  Here’s the simple scenario.  I’m going to use a common “Customer” class that I want to use in both a WPF and Silverlight implementation.  Since there is no binary compatibility for Silverlight and WPF, I’m going to maintain source-level compatibility.  In order to do this, I’m going to create a Silverlight Class Library project and implement my Customer class in that…here’s my simple customer class:

   1: namespace SilverlightClassLibrary1
   2: {
   3:     public class Customer
   4:     {
   5:         public string FirstName { get; set; }
   6:         public string LastName { get; set; }
   7:         public int CustomerId { get; set; }
   8:         public string CustomerLevel { get; set; }
   9:         public DateTime Birthdate { get; set; }
  10:  
  11:         public static ObservableCollection<Customer> GetCustomerData()
  12:         {
  13:             ObservableCollection<Customer> ppl = new ObservableCollection<Customer>();
  14:  
  15:             ppl.Add(new Customer() { FirstName = "Tim", LastName = "Heuer", CustomerId = 1, CustomerLevel = "Platinum", Birthdate = Convert.ToDateTime("9/18/1965") });
  16:             ppl.Add(new Customer() { FirstName = "Ray", LastName = "Ozzie", CustomerId = 1, CustomerLevel = "Gold", Birthdate = Convert.ToDateTime("1/12/1960") });
  17:             ppl.Add(new Customer() { FirstName = "Bill", LastName = "Gates", CustomerId = 1, CustomerLevel = "Silver", Birthdate = Convert.ToDateTime("12/1/1976") });
  18:             ppl.Add(new Customer() { FirstName = "Bart", LastName = "Simpson", CustomerId = 1, CustomerLevel = "Tin", Birthdate = Convert.ToDateTime("7/4/1985") });
  19:  
  20:             return ppl;
  21:         }
  22:     }
  23: }

Now in my Silverlight project and my WPF application I add a linked file to that class library for customer.  While not binary compat, each time I compile I’m using a common source compat for both projects.  Here’s what my project structure looks like and you can see the linked source code:

Now in my WPF project I want to add some XAML, so I’ll add this to my Window1.xaml:

   1: <Window x:Class="WpfSampler.Window1"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:controls="clr-namespace:Microsoft.Windows.Controls;assembly=WPFToolkit"
   5:     Title="Window1" Height="600" Width="600">
   6:     <Grid>
   7:         <StackPanel Orientation="Vertical" Margin="15">
   8:             <TextBlock Text="Your Birthdate" />
   9:             <controls:DatePicker x:Name="MyBirthdate" Text="9/18/1965" />
  10:             <controls:DataGrid Height="400" x:Name="CustomerList"/>
  11:         </StackPanel>
  12:     </Grid>
  13: </Window>

Here’s the backing source code logic for the simple windows app:

   1: namespace WpfSampler
   2: {
   3:     /// <summary>
   4:     /// Interaction logic for Window1.xaml
   5:     /// </summary>
   6:     public partial class Window1 : Window
   7:     {
   8:         public Window1()
   9:         {
  10:             InitializeComponent();
  11:             Loaded += new RoutedEventHandler(Window1_Loaded);
  12:         }
  13:  
  14:         void Window1_Loaded(object sender, RoutedEventArgs e)
  15:         {
  16:             CustomerList.ItemsSource = SilverlightClassLibrary1.Customer.GetCustomerData();
  17:         }
  18:     }
  19: }

Now in my Silverlight project I’m going to paste the same XAML:

   1: <UserControl x:Class="SilverlightWpfReuse.Page"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
   4:     xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"
   5:     xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
   6:     Width="600" Height="600">
   7:     <Grid x:Name="LayoutRoot" Background="White">
   8:         <StackPanel Orientation="Vertical" Margin="15">
   9:             <TextBlock Text="Your Birthdate" />
  10:             <controls:DatePicker x:Name="MyBirthdate" Text="9/18/1965" />
  11:             <data:DataGrid Height="400" x:Name="CustomerList"/>
  12:         </StackPanel>
  13:     </Grid>
  14: </UserControl>

and here’s the Silverlight source code logic as well:

   1: namespace SilverlightWpfReuse
   2: {
   3:     public partial class Page : UserControl
   4:     {
   5:         public Page()
   6:         {
   7:             InitializeComponent();
   8:             Loaded += new RoutedEventHandler(Page_Loaded);
   9:         }
  10:  
  11:         void Page_Loaded(object sender, RoutedEventArgs e)
  12:         {
  13:             CustomerList.ItemsSource = SilverlightClassLibrary1.Customer.GetCustomerData();
  14:         }
  15:     }
  16: }

So if you have a keen eye you’ll see it’s not full cut/paste as you note the xmlns declarations in the root control.  Since the implementations are in two different assemblies (System.Windows.Controls.dll for Silverlight and Microsoft.Windows.Controls.dll for WPF Toolkit) we have to make sure they are referenced accordingly.  We can still use the same prefix though of “controls” so that we have greater re-use across our XAML.  For DataGrid, we need to do an additional step since for Silverlight it is on its own assembly.

If we run these applications here is what we get:

WPF Application:

Silverlight application:

Sure we had to do some maneuvering (xmlns stuff) but if you have some great XAML/code you can still get some good re-use out of those implementations with little effort and share code!

So what about VisualStateManager?  How do you use that in WPF if you already have something in Silverlight?  Let’s simplify it to the most common/basic control – Button.  Using Blend we’ve styled a simple Button control and Blend has generated the appropriate VSM resources for us (note that I am not a designer and just used Blend to quickly make 2 changes that probably look horrible :-):

   1: <Style x:Key="StyledButton" TargetType="Button">
   2:             <Setter Property="Background" Value="#FF1F3B53"/>
   3:             <Setter Property="Foreground" Value="#FF000000"/>
   4:             <Setter Property="Padding" Value="3"/>
   5:             <Setter Property="BorderThickness" Value="1"/>
   6:             <Setter Property="BorderBrush">
   7:                 <Setter.Value>
   8:                     <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
   9:                         <GradientStop Color="#FFA3AEB9" Offset="0"/>
  10:                         <GradientStop Color="#FF8399A9" Offset="0.375"/>
  11:                         <GradientStop Color="#FF718597" Offset="0.375"/>
  12:                         <GradientStop Color="#FF617584" Offset="1"/>
  13:                     </LinearGradientBrush>
  14:                 </Setter.Value>
  15:             </Setter>
  16:             <Setter Property="Template">
  17:                 <Setter.Value>
  18:                     <ControlTemplate TargetType="Button">
  19:                         <Grid>
  20:                             <vsm:VisualStateManager.VisualStateGroups>
  21:                                 <vsm:VisualStateGroup x:Name="CommonStates">
  22:                                     <vsm:VisualState x:Name="Normal"/>
  23:                                     <vsm:VisualState x:Name="MouseOver">
  24:                                         <Storyboard>
  25:                                             <DoubleAnimationUsingKeyFrames Storyboard.TargetName="BackgroundAnimation" Storyboard.TargetProperty="Opacity">
  26:                                                 <SplineDoubleKeyFrame KeyTime="0" Value="1"/>
  27:                                             </DoubleAnimationUsingKeyFrames>
  28:                                             <ColorAnimationUsingKeyFrames Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
  29:                                                 <SplineColorKeyFrame KeyTime="0" Value="#F2FFFFFF"/>
  30:                                             </ColorAnimationUsingKeyFrames>
  31:                                             <ColorAnimationUsingKeyFrames Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)">
  32:                                                 <SplineColorKeyFrame KeyTime="0" Value="#CCFFFFFF"/>
  33:                                             </ColorAnimationUsingKeyFrames>
  34:                                             <ColorAnimationUsingKeyFrames Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)">
  35:                                                 <SplineColorKeyFrame KeyTime="0" Value="#7FE61212"/>
  36:                                             </ColorAnimationUsingKeyFrames>
  37:                                             <ColorAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="Background" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)">
  38:                                                 <SplineColorKeyFrame KeyTime="00:00:00" Value="#FFEE4B4B"/>
  39:                                             </ColorAnimationUsingKeyFrames>
  40:                                         </Storyboard>
  41:                                     </vsm:VisualState>
  42:                                     <vsm:VisualState x:Name="Pressed">
  43:                                         <Storyboard>
  44:                                             <ColorAnimationUsingKeyFrames Storyboard.TargetName="Background" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)">
  45:                                                 <SplineColorKeyFrame KeyTime="0" Value="#FFF40B0B"/>
  46:                                             </ColorAnimationUsingKeyFrames>
  47:                                             <DoubleAnimationUsingKeyFrames Storyboard.TargetName="BackgroundAnimation" Storyboard.TargetProperty="Opacity">
  48:                                                 <SplineDoubleKeyFrame KeyTime="0" Value="1"/>
  49:                                             </DoubleAnimationUsingKeyFrames>
  50:                                             <ColorAnimationUsingKeyFrames Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[0].(GradientStop.Color)">
  51:                                                 <SplineColorKeyFrame KeyTime="0" Value="#D8FFFFFF"/>
  52:                                             </ColorAnimationUsingKeyFrames>
  53:                                             <ColorAnimationUsingKeyFrames Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[1].(GradientStop.Color)">
  54:                                                 <SplineColorKeyFrame KeyTime="0" Value="#C6FFFFFF"/>
  55:                                             </ColorAnimationUsingKeyFrames>
  56:                                             <ColorAnimationUsingKeyFrames Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[2].(GradientStop.Color)">
  57:                                                 <SplineColorKeyFrame KeyTime="0" Value="#8CFFFFFF"/>
  58:                                             </ColorAnimationUsingKeyFrames>
  59:                                             <ColorAnimationUsingKeyFrames Storyboard.TargetName="BackgroundGradient" Storyboard.TargetProperty="(Rectangle.Fill).(GradientBrush.GradientStops)[3].(GradientStop.Color)">
  60:                                                 <SplineColorKeyFrame KeyTime="0" Value="#3FFFFFFF"/>
  61:                                             </ColorAnimationUsingKeyFrames>
  62:                                         </Storyboard>
  63:                                     </vsm:VisualState>
  64:                                     <vsm:VisualState x:Name="Disabled">
  65:                                         <Storyboard>
  66:                                             <DoubleAnimationUsingKeyFrames Storyboard.TargetName="DisabledVisualElement" Storyboard.TargetProperty="Opacity">
  67:                                                 <SplineDoubleKeyFrame KeyTime="0" Value=".55"/>
  68:                                             </DoubleAnimationUsingKeyFrames>
  69:                                         </Storyboard>
  70:                                     </vsm:VisualState>
  71:                                 </vsm:VisualStateGroup>
  72:                                 <vsm:VisualStateGroup x:Name="FocusStates">
  73:                                     <vsm:VisualState x:Name="Focused">
  74:                                         <Storyboard>
  75:                                             <DoubleAnimationUsingKeyFrames Storyboard.TargetName="FocusVisualElement" Storyboard.TargetProperty="Opacity">
  76:                                                 <SplineDoubleKeyFrame KeyTime="0" Value="1"/>
  77:                                             </DoubleAnimationUsingKeyFrames>
  78:                                         </Storyboard>
  79:                                     </vsm:VisualState>
  80:                                     <vsm:VisualState x:Name="Unfocused"/>
  81:                                 </vsm:VisualStateGroup>
  82:                             </vsm:VisualStateManager.VisualStateGroups>
  83:                             <Border x:Name="Background" Background="White" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="3">
  84:                                 <Grid Margin="1" Background="{TemplateBinding Background}">
  85:                                     <Border x:Name="BackgroundAnimation" Opacity="0" Background="#FF448DCA"/>
  86:                                     <Rectangle x:Name="BackgroundGradient">
  87:                                         <Rectangle.Fill>
  88:                                             <LinearGradientBrush EndPoint=".7,1" StartPoint=".7,0">
  89:                                                 <GradientStop Color="#FFFFFFFF" Offset="0"/>
  90:                                                 <GradientStop Color="#F9FFFFFF" Offset="0.375"/>
  91:                                                 <GradientStop Color="#E5FFFFFF" Offset="0.625"/>
  92:                                                 <GradientStop Color="#C6FFFFFF" Offset="1"/>
  93:                                             </LinearGradientBrush>
  94:                                         </Rectangle.Fill>
  95:                                     </Rectangle>
  96:                                 </Grid>
  97:                             </Border>
  98:                             <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" x:Name="contentPresenter" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}"/>
  99:                             <Rectangle x:Name="DisabledVisualElement" IsHitTestVisible="false" Opacity="0" Fill="#FFFFFFFF" RadiusX="3" RadiusY="3"/>
 100:                             <Rectangle Margin="1" x:Name="FocusVisualElement" IsHitTestVisible="false" Opacity="0" Stroke="#FF6DBDD1" StrokeThickness="1" RadiusX="2" RadiusY="2"/>
 101:                         </Grid>
 102:                     </ControlTemplate>
 103:                 </Setter.Value>
 104:             </Setter>
 105:         </Style>

There is nothing more we have to do in Silverlight since VSM is a part of the core.  We just annotate our Button with the style:

   1: <Button Content="Styled Button" Style="{StaticResource StyledButton}" />

Now in WPF we can use those same resources by adding them to our Grid.Resources node in our Window1.xaml file.  The thing is that we don’t need the vsm: prefix.  A simple find/replace removes them and we have our style button.  The resulting full XAML for the style looks the exact same (minus any vsm: prefix) and the XAML for the button also looks the same.

I think there has to be a better way to use linked files here as well, so I’ll think about that and report back if I find one.  I know this is a very simple demonstration of only a bit beyond Hello World, but I hope at least it gets you thinking of how you can get source-level compatibility and some XAML re-use out of your Silverlight and WPF applications. 

What are your thoughts?  Have you found better ways?  What are the stumbling blocks you are facing in code sharing?

| Comments

Over the past few months Joel and I have been back-and-forthing modifications to his original great idea and goal “build a re-sizable video player using no custom user controls, but instead leveraging controls styles and templates.”  Joel started in Silverlight 2 Beta 1 and implemented using the style method (aka ‘the MIX model’) available at that time. 

I took it and added some functionality of scaling and startup parameters.  After the VisualStateManager model for styling was released, this project made perfect sense to demonstrate those abilities and thus I transformed the great styling work that Joel did into the VSM model.

Joel has since gone back into the project and implemented media marker support and an enhanced user interface to display them.  I found one issue in his marker implementation and emailed him about it with a suggestion that (reading between the lines) loosely translated was: how about we stop emailing this project and open source it?

The next day Joel has pushed the project to Codeplex.  Introducing Silverlight 2 – Video Player

Here's a running sample:

The current implementation is up there (with an already work item suggested by me :-)).  Awesome!  Joel chose the Common Development and Distribution License which I think is very similar to the less wordy (by 2,153 words) Microsoft Public License, both of which are approved OSI licenses for open source.

UPDATE: Joel has changed to use the Ms-Pl license on the project!

Thanks to Joel for putting it out there as an open source project.  Some simple code but hopefully will help those using Silverlight and media create quick experiences with an embeddable, skinnable solution!

Related posts:

| 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

One of the things I love about the Microsoft developer ecosystem is the partner channels that are enabled to create great add-ons to our platforms and frameworks.  Our partners in this space usually get to the better implementations before we do, taking on the task of filling some gaps in unique implementations while our teams can focus on providing the best framework for enabling that construction.

In December of last year, Telerik showed their intentions of making a control suite for Silverlight (then v1.1).  Well now that beta 2 is released for Silverlight 2, they’ve updated their RadControls for Silverlight 2 suite and have now provided a downloadable CTP of the suite.

Their controls implement support for DataBinding, the new VisualStateManager model, Templates/Styles, etc.  Some of the controls they are providing are some that you may find interesting or enhance the existing control suite from the Silverlight core:

    • Menu
    • TreeView
    • Upload
    • RadCube
    • RadNumericUpDn
    • RadProgressBar
    • Animation framework

One of their key features is they’ve decided to make these source code compatible with WPF.  The full WPF are not yet available.  You can download the CTP for free right now on their site and view some sample implementations on their sample site.

Telerik is widely known for providing great products and this is really great to see them provide controls for Silverlight that are also compatible with WPF.  I’m excited to see this control suite evolve to release state and perhaps more from the Silverlight team at Telerik!

| 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!