Page view counter

April 2009 - Posts

Animated Visual State Transitions with the Transitioning Content Control

 

The Silverlight Toolkit is innovative in many ways, not least of which is that controls are released in one of four quality bands:

  • Mature: ready for release
  • Stable: suitable for most scenarios
  • Preview: suitable for most basic usage scenarios, may have moderate number of breaking changes as the control is developed.
  • Experimental: intended for evaluation purposes

The control I’ll be considering today was developed (and described here) by Ruurd Boeke and is currently in the Experimental band. You can expect that the API will change quite a bit, but that said, it is an enormously useful control right now; and thus I’ve submitted a video and this write-up.

What’s It For?

The goal of the Transitioning Content control is to make it easy to add animation when you are changing content within a control as demonstrated here. [You’ll need to click on DomainUpDown on the left (and surprisingly, not on TransitioningContent!) and Animations on top. The following cropped image illustrates where to click, but provides only a shadow of the impact

DemoTransition

Getting There In 3 Steps

To make this crystal clear, and to show how easy it really is to use this control, we’ll build the example three times: first with a Content Control, then with a Transitioning Content Control, and finally, adding data binding and the ability to transition more complex objects.

Starting Simple

Version 0 begins with a grid with two columns. The left column contains a ContentControl and the right a button. Here is the complete Xaml:

<UserControl x:Class="tccDemo.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="300" Height="150">
<StackPanel Background="Bisque">

<ContentControl x:Name="cc1"
Content="Click button to change."
HorizontalAlignment="Center"
Margin="20"
FontSize="18" />

<Button x:Name="doChange"
Content="Change"
Width="80"
Height="30"
HorizontalAlignment="Center"
FontSize="14"/>

</StackPanel>
</UserControl>

The job of the ContentControl is to hold a single piece of content: in this case a string. The button’s job is to cause that content to change, which we do programmatically in the button’s click event handler in MasterPage.xaml.cs, shown in full:

using System;
using System.Windows;
using System.Windows.Controls;

namespace tccDemo
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
doChange.Click += new RoutedEventHandler( doChange_Click );
}

void doChange_Click( object sender, RoutedEventArgs e )
{
Random random = new Random();
cc1.Content = random.NextDouble().ToString();
}
} // end class
} // end namespace

Each time the button is clicked, a new value is displayed.

For more on Skinnable Custom Controls, see the blog series that starts here, or consider these videos (click on the image to go to the video):

SkinnableCustomControlsPart1a SkinnableCustomControlsPart2a
SkinnableCustomControlsPart3 SkinnableCustomControlsPart4

Before we dive into the TransitioiningContent control and how it does its work, let’s look at how to use it. We start by replacing the ContentControl with a TransitioningContentControl, but to do this we need to add a reference to System.Windows.Controls.Layout.Toolkit in the references and a namespace to the top of the Xaml file

xmlns:layout="clr-namespace:System.Windows.Controls;
assembly=System.Windows.Controls.Layout.Toolkit"

With that in place we can modify MainPage.xaml to replace the ContentControl with the TransitioningContentControl and replace the Change button with two buttons: one for Up and one for down. Here is the complete Xaml:

<UserControl x:Class="tccDemo.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:layout="clr-namespace:System.Windows.Controls;
assembly=System.Windows.Controls.Layout.Toolkit"
Width="400" Height="200">
<StackPanel Background="Bisque">
<layout:TransitioningContentControl x:Name="tcc"
HorizontalAlignment="Center"
Margin="30"
FontSize="18"
Content="Click buttons to change content" />

<Button x:Name="UpButton"
Content="Up"
Width="100"
Height="30"
Margin="10"
FontSize="14"/>
<Button x:Name="DownButton"
Content="Down"
Width="100"
Height="30"
Margin="10"
FontSize="14"/>
</StackPanel>
</UserControl>

The code is modified only to set the Transition property of the TransitioningContentControl.  Here is the complete code behind file:

using System;
using System.Windows;
using System.Windows.Controls;

namespace tccDemo
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
UpButton.Click += new RoutedEventHandler( UpButton_Click );
DownButton.Click += new RoutedEventHandler( DownButton_Click );
}

void DownButton_Click( object sender, RoutedEventArgs e )
{
tcc.Transition = "DownTransition";
Random random = new Random();
tcc.Content = random.NextDouble().ToString();
}

void UpButton_Click( object sender, RoutedEventArgs e )
{
tcc.Transition = "UpTransition";
Random random = new Random();
tcc.Content = random.NextDouble().ToString();
}

}
}

Here is the effect:

Adding DataBinding and Objects

In both of the examples so far, the content has been a simple string. It is possible, however, to provide a more complex object, by modifying the TransitioningContentControl and using an explicit ContentTemplate.

<layout:TransitioningContentControl   
x:Name="tcc"
Margin="20"
FontSize="18"
HorizontalAlignment="Center"
Content="Use buttons...">
<layout:TransitioningContentControl.ContentTemplate>
<DataTemplate>
<StackPanel >
<TextBlock Text="{Binding Title }"
FontFamily="Georgia"
FontSize="14" />
<TextBlock Text="{Binding Author }"
FontFamily="Georgia"
FontSize="14" />
</StackPanel>
</DataTemplate>
</layout:TransitioningContentControl.ContentTemplate>
</layout:TransitioningContentControl>

This follows all the normal conventions of using a ContentTemplate. We fill it with a DataTemplate which holds a StackPanel, allowing us to place two TextBlocks, both of which use binding syntax to indicate that they are going to bind to the Title and Author properties of whatever object they are given, respectively.

The rest of the Xaml file is unchanged.

We need a data object, and so we create as simple a data object as possible to illustrate this idea; noting that of course you can get your data from a database, from an XML file, etc.  Here is the complete contents of Book.cs including the static property we’ll use to obtain some pre-created data,

using System.Collections.Generic;

namespace tccDemo
{
public class Book
{
public string Title { get; set; }
public string Author { get; set; }

public static List<Book> Books
{
get
{
List<Book> theBooks = new List<Book>();
theBooks.Add( new Book()
{ Title = "The Raw Shark Texts", Author = "Steven Hall" } );
theBooks.Add( new Book()
{ Title = "Columbine", Author = "Dave Cullen" } );
theBooks.Add( new Book()
{ Title = "Unfriendly Fire", Author = "Dr. Nathaniel Frank" } );
theBooks.Add( new Book()
{ Title = "The Inheritance", Author = "Dave Sanger" } );
theBooks.Add( new Book()
{ Title = "Sir Gawain and the Green Knight",
Author = "Simon Armitage" } );
theBooks.Add( new Book()
{ Title = "The Superorganism", Author = "Holldobler and Wilson" } );
return theBooks;
}
}
}
}

 

MainPage.xaml.cs is modified somewhat more significantly, to hold a membervariable of type List<Book> (thus avoiding having to “get” the data repeatedly) and a counter as a convenience so that we can cycle through our somewhat meager collection.  Here is the complete MainPage.xaml.cs

using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;

namespace tccDemo
{
public partial class MainPage : UserControl
{

private List<Book> books = Book.Books;
private int counter = 0;

public MainPage()
{
InitializeComponent();
tcc.Transition = "Normal";
tcc.Content = books[counter++];
UpButton.Click += new RoutedEventHandler( UpButton_Click );
DownButton.Click += new RoutedEventHandler( DownButton_Click );
}

void UpButton_Click( object sender, RoutedEventArgs e )
{
tcc.Transition = "UpTransition";
tcc.Content = GetBook();
}

void DownButton_Click( object sender, RoutedEventArgs e )
{
tcc.Transition = "DownTransition";
tcc.Content = GetBook();
}

public Book GetBook()
{
if ( ++counter >= books.Count )
counter = 0;
return books[counter];
}
}
}

The constructor sets the initial visual state to Normal and sets the content of the TransitioningContentControl to the first book in the collection. It then sets up the two event handlers. The job of each is to set the Transition state and then call the helper method that gets the next book in the collection.

Visual State Ambivalence

The TransitioningContent is a bit ambivalent about its visual states. There are four states that are hardwired into the control as it is currently written:

  • Default
  • Normal
  • UpTransition
  • DownTransition

However, if you examine the attributes at the top of the class (used to signal, for example, both the Visual State Manager and tools like Blend what visual states the class supports) you’ll find this:

[TemplateVisualState(GroupName = PresentationGroup, 
Name = NormalState)]
[TemplateVisualState(GroupName = PresentationGroup,
Name = DefaultTransitionState)]

[TemplatePart(Name = PreviousContentPresentationSitePartName,
Type = typeof(ContentControl))]
[TemplatePart(Name = CurrentContentPresentationSitePartName,
Type = typeof(ContentControl))]
public class TransitioningContentControl : ContentControl

There are precisely two visual states made visible to Blend and the VSM.  The net effect is that you can certainly use the UpTransition and DownTransition, but they were added as examples of how you can freely extend this class with any transitions you like.

Here’s how it works. The TransitioningContentControl consists of two parts both of type ContentControl: PreviousContentPresentationSitePartName and CurrentContentPresentationSitePartName. 

To add an animated transition from content A to content B you need only hand the two to this control and tell it, by passing in a string, what storyboard to invoke.  If you pass in the string TransitionUp or TransitionDown then it already knows what storyboard to invoke, as Ruurd Boeke wrote those and put them in the Resources section of TransitioningContentControl.xaml.  Here, for example, is his UpTransition:

<vsm:VisualState x:Name="UpTransition">
<Storyboard>
<DoubleAnimationUsingKeyFrames
BeginTime="00:00:00"
Storyboard.TargetName="CurrentContentPresentationSite"
Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.300" Value="1"/>
</DoubleAnimationUsingKeyFrames>

<DoubleAnimationUsingKeyFrames
BeginTime="00:00:00"
Storyboard.TargetName="CurrentContentPresentationSite"
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[3].(TranslateTransform.Y)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="30"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.300" Value="0"/>
</DoubleAnimationUsingKeyFrames>

<DoubleAnimationUsingKeyFrames
BeginTime="00:00:00"
Storyboard.TargetName="PreviousContentPresentationSite"
Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.300" Value="0"/>
</DoubleAnimationUsingKeyFrames>

<DoubleAnimationUsingKeyFrames
BeginTime="00:00:00"
Storyboard.TargetName="PreviousContentPresentationSite"
Storyboard.TargetProperty="(UIElement.RenderTransform).
(TransformGroup.Children)[3].(TranslateTransform.Y)">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.300" Value="-30"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>

The effect of this is to target first the opacity of the current content, which will go from 0 to 1 over 3/10 of a second. During that same time period it will move up the Y axis from 30 to 0 (remember that the Y axis counts up as it moves down the screen).  In the second half of the animation the targetproperty is the opacity of the previous content which fades away from 1 to 0 over that same 3/10 of a second, while the content itself moves up from 0 to –30.

Notice that the storyboard is within the VisualState whose name is UpTransition.

The class itself has a public property named Transition:

/// <summary>
/// Gets or sets the name of the transition to use.
/// These correspond directly to the VisualStates inside
/// the PresentationStates group.
/// </summary>
public string Transition
{
get { return GetValue(TransitionProperty) as string; }
set { SetValue(TransitionProperty, value); }
}

This acts as a front for the Dependency Property which is registered immediately below

public static readonly DependencyProperty TransitionProperty =
DependencyProperty.Register(
"Transition",
typeof(string),
typeof(TransitioningContentControl),
new PropertyMetadata(OnTransitionPropertyChanged));

A quick review of the Silverlight documentation reveals the meaning of each of the four parameters:

DPRegister

Notice that the type of the TransitionProperty is string, and parenthetically, notice that the final parameter, typeMetadata,  is explicitly noted for usage with a PropertyChangedCallback, which is what is done here.

OnTransitionPropertyChanged is overloaded in the implementation, but the net effect is to set the source of the content control and to set the string representing the new transition and then to call ChangeTransition whose job is to make sure it is safe to set a new transition, and then to obtain the PresentationState Visual State group and then to look to see if there is a state for the string passed in. If so, that transition is set as the new value for the transition.

Thus, with this somewhat unusual control,  you can modify the visual states within the PresentationGroup) without subclassing, and by doing so (and providing a storyboard) you can add any transition you like, which you can then invoke by passing in its name!

Caveat! As noted earlier, this control is in the experimental band, and this API is very likely to change.

I hope you found this bit of control spelunking as interesting as I did sorting it out; and it is just fine to set all of the details aside and just use the control in conjunction with other controls to create animated transitions without over-worrying about how it is doing its magic.

The State of Things – A Brief Review Before Tech Ed.

I think it is fair to say that interest in Silverlight is wicked-high.

  • Twitter grades. Jesse: 99.5th percentile; Tim: 99.8th percentile!
  • Between us Feedburner shows more than 10,000 subscribers
  • 31 Silverlight Sessions at Mix, 30 at Tech Ed
  • LiveSearch of “Silverlight” returns 450 million pages
  • Amazon lists over 500 books on the topic!

And with all of that comes a very serious responsibility on our part to meet the needs both of new Silverlight programmers and those of you who’ve been with us since hieroglyphics.  My goal: how can we increase the immediate and long term utility of the information we’re providing?

More Useful Information Through Listening

It starts by shutting up and listening (admittedly not my strong suit).

We’ve been taking every opportunity to speak world wide at industry gatherings large and not so large.  While I’m blasted to be presenting at Tech Ed, it is also true that community and regional events like Code Mash  can be CodeMashLogoterrific opportunities to talk to programmers who I might not get as much of a chance to sit down with at the larger shows.

At this year’s Mix I skipped a number of presentations to spend more time in the Third Place, and no surprise it was time incredibly well spent. I’ve been sitting in on Ask the Expert Sessions, spending more time on Twitter, Facebook and other social networks and generally finding that developers are more than eager to let us know what they need, if only we’ll be quiet enough to listen. And respond.

Last year, about this time the community asked for more end-to-end projects. Thus were born numerous innovations, most notable of which is Tim’s Application Corner and, more recently, my ongoing glass-window design and coding of a VideoWiki. 

I’m extremely happy to say that the VideoWiki project will benefit from the assistance and collaboration of a number of extraordinary people both inside and outside of Microsoft.

Even as we speak I am working actively with that most gifted of Animation and development/design experts, Jeff Paries.  We will soon blog our rough design ideas, and then walk through the decision processes, the creation of wireframes and more. But I digress.

More Useful Information Through Innovation

signalNoise While our How Do I videos remain extremely popular, some folks would rather read than watch; and thus was born both the Silverlight Tutorials, but also my experiment in writing mini-tutorials within my blog, and here my ego takes over and I must show off that  while my Twittalyzer scores are generally pathetic, my Signal to Noise ratio just hit 100%! – as promised: More signal, Less noise.

Better Information Through Intensive Collaboration

Tim and I are teaming up with Laurence Moroney and many others inside Microsoft,  transcending false internal “boundaries” and creating collaboration across organizations. That model is proving out not only with Evangelists, but also with developers; more and more we are crossing old lines and creating new and effective virtual teams.  (Do I get points for not saying syn**gy?)

Better Performance Through Recognizing How Much Is Left To Be Done

Before we get too happy with ourselves, there is much more to do on all these fronts (and many more); but folks at Silverlight.net (and our sister sites) are very committed as are, as you know by their incredible productivity, the teams writing the code.

What’s On Deck?

My own list, just of material I hope to provide in the next few months, is staggering. The number of topics for my blog, VideoWiki, videos, tutorials, book, and presentations is a wonderful and absurd and magnificent shot of main-line enthusiasm and I can safely report to you, after nearly two years into my one year stint at Microsoft, that I’ve barely begun. 

jesseSigColorMatchForBlog

Tomorrow’s blog entry: Transition Content Control.
This week: Next step in the WiKi Design

Posted by jesseliberty | 2 comment(s)
Filed under: ,

Easing is… Easier

For those who have been wondering “Where’s Jesse??” the answer is that I’ve been head’s down preparing for my presentation at Tech Ed (you are going to Tech Ed aren’t you?!) 

Microsoft has three major conferences. The following is my personal description:

-- PDC – What is coming in the next few years. The BIG conference.
-- Tech Ed – What is the current state of the art. – Dive deep with geeks
-- Mix – Let’s get developers and designers together and create magic.



I have not abandoned any of my other projects; and all will be ramped back up to full speed as soon as my presentation is ready.  In the meantime, this entry is a brief exploration of Easing in Silverlight 3 and Blend 3.


A Note About Reduced Blogging
HeroinIt’s hard cutting down on blogging. I’ve been experience  sweating, malaise,  chills and compulsive scratching.  Hmmm….

 

In Silverlight 2, Easing Wasn’t Obvious

One aspect of animation that has always looked more difficult than it really is, is easing

OldEasingFirst, the term itself is a bit intimidating to those of us who are not specialists: what exactly is being eased?  Second, it is usually introduced like this: “oh, and then you can double click on the animation and adjust the easing. Drag the yellow dots until the easing gives you the effect you want…

The problem of course is that this presupposes that you know what easing is and what effect you want.  Happily, Silverlight 3 and Blend 3 make all of this much more straight forward.

What Are We Trying To Do?

First, let’s get the fundamentals straight:

  • Easing is a term of art for modifying an animation so that the rate of change is not uniform: specifically so that you can introduce acceleration or deceleration
  • In refers to easing at the start of the animation
  • Out refers to easing at the end of the animation

Straight Line Acceleration

EllipseAnimationStep 1 might be to create an animation that moves a dot from a starting point to an ending point over 1 second.

The animation engine is going to divide the distance it has to move the dot over the one second you’ve allocated.  The effect is that the dot moves smoothly and at the same speed from beginning to end.

Its speed is uniform.  However, (and don’t panic!)  what we care about is not just speed but acceleration.

Without setting the easing your acceleration is, essentially infinite; the object moves from 0 to its uniform velocity in zero time. Unfortunately, things don’t do that in the real world.

 

 

 

 

StraightLineEasing 

 

 

Changing the Rate of Acceleration

We are used to the Newtonian laws of physics if only intuitively. Imagine watching a movie in which an old fashioned steam engine railroad is shown.  If it went from standing at the station, emitting steam, passengers embarking and the conductor calling out “’Board!” to 60 MPH with no acceleration we’d fall over laughing.  We have fully incorporated the assumption that the train will start out painfully slowly, building speed as it goes.

This is true of everything in our environment, and adding even a little bit of acceleration or deceleration can provide a subtle, even unconscious verisimilitude to animation that moves your animated effect from cartoon like to professional.

And there’s the rub: in Silverlight 2 this felt like the province of designers and other professionals who knew what they were doing with those tiny yellow dots and funny curves. 

Silverlight 3 Makes It Easy, and Teaches What It Is Doing

EasingNew In Silverlight 3 you can still create your own hand-drawn easing, but the common easing functions have been created already. Instead of leaving you with a line and a graph to draw the line on, the new easing setting lets you pick the curve you’d like. That, and a quick translation of what these curves mean, and suddenly all the mystery disappears.

The first thing to notice is that you can just click on the easing you want (Back, Bounce, Circle, Cubic) and within each you have your choice of one of three modes (In, Out, In/Out).

Now, about those nasty curves….

Easing Is A Function

Easing is accomplished by a (usually) simple function. It works like this: the acceleration (or deceleration) will change as a function of time.  That means, as time passes, the acceleration will increase.

With no easing the function looks like this:cubes

ftt

You read that the function of time is equal to time, or in English: the acceleration will increase uniformly over time.

With that, it is easy to go to the CubicEase

ft3 

Thus after three units of time passes, you should see 9 times the acceleration. You would expect that if you had a cubic easing at the beginning of the animation (In mode) that you’d see a fairly radical bend upwards in the curve. Consider what happens to f(t) as t goes from 1 to 5 (shown in the small table on the right)

You can see the radical bend in the curve shown in the graph in the help files (excerpt in image below)
and in the drop-down in Blend (above)

CubicEaseClass

An Example To Bring It Home

To see this at work, I created an example that lets you pick from a few different easing functions and to set any of the three modes. Let’s take a quick look at the surprisingly straight forward code.  The following is the complete Xaml,

<UserControl x:Class="EasingChoices.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400"
Height="500">
<!-- I’ve divided my page into an upper part for the animation
and a lower part for the controls. -->
  <Grid x:Name="OuterGrid"
Background="Bisque">
<Grid.RowDefinitions>
<RowDefinition Height="3*" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>

<!-- One storyboard and its animation.
Note that the animation is given a name as we’ll address it programmatically. -->
<StackPanel x:Name="LayoutRoot"
Background="White"
Grid.Row="0">
<StackPanel.Resources>
<Storyboard x:Name="myStoryboard">
<DoubleAnimation x:Name="theAnimation"
From="0"
To="200"
Duration="00:00:3"
Storyboard.TargetName="myRectangle"
Storyboard.TargetProperty="Height">
</DoubleAnimation>
</Storyboard>
</StackPanel.Resources>

<!--The object we'll be animating-->
<Rectangle x:Name="myRectangle"
Fill="Blue"
Width="200"
Height="30" />
</StackPanel>

<!--The inner grid holds the radio buttons-->
<Grid x:Name="innerGrid"
ShowGridLines="False"
Grid.Row="1 ">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>

<!—First of two stack panels-->

<StackPanel Grid.Column="1">
<RadioButton x:Name="Bounce"
GroupName="Easing"
Content="Bounce"
HorizontalAlignment="Left"
VerticalAlignment="Center"
IsChecked="True"
Margin="10"
FontSize="18" />
<RadioButton x:Name="Sine"
GroupName="Easing"
Content="Sine"
HorizontalAlignment="Left"
VerticalAlignment="Center"
IsChecked="False"
Margin="10"
FontSize="18" />
<RadioButton x:Name="Power"
GroupName="Easing"
Content="Power"
HorizontalAlignment="Left"
VerticalAlignment="Center"
IsChecked="False"
Margin="10"
FontSize="18" />
</StackPanel>

<!--Second stack panel-->
<StackPanel Grid.Column="2">
<RadioButton x:Name="In"
GroupName="Mode"
Content="In"
HorizontalAlignment="Left"
VerticalAlignment="Center"
IsChecked="True"
Margin="10"
FontSize="18" />
<RadioButton x:Name="Out"
GroupName="Mode"
Content="Out"
HorizontalAlignment="Left"
VerticalAlignment="Center"
IsChecked="False"
Margin="10"
FontSize="18" />
<RadioButton x:Name="InOut"
GroupName="Mode"
Content="In/Out"
HorizontalAlignment="Left"
VerticalAlignment="Center"
IsChecked="False"
Margin="10"
FontSize="18" />
</StackPanel>
</Grid>
</Grid>
</UserControl>

The supporting code responds to any button being checked by creating a new EasingFunction and telling the animation to use our new function rather than the one that appears in the Xaml.  To do this we take advantage of the fact that all the easing functions (BounceEase, SineEase, etc.) derive from a common base class: EasingFunctionBase.

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Animation;

namespace EasingChoices
{
public partial class MainPage : UserControl
{
EasingFunctionBase easingFunction = null;

public MainPage()
{
InitializeComponent();

// all events call same handler
Bounce.Checked += new RoutedEventHandler( CreateNewEasingFunction );
Power.Checked += new RoutedEventHandler( CreateNewEasingFunction );
Sine.Checked += new RoutedEventHandler( CreateNewEasingFunction );
In.Checked += new RoutedEventHandler( CreateNewEasingFunction );
Out.Checked += new RoutedEventHandler( CreateNewEasingFunction );
InOut.Checked += new RoutedEventHandler( CreateNewEasingFunction );
}



private void CreateNewEasingFunction(object sender, RoutedEventArgs e)
{
if ( Bounce.IsChecked == true )
easingFunction = new BounceEase();
if (Sine.IsChecked == true )
easingFunction = new SineEase();
if ( Power.IsChecked == true )
easingFunction = new PowerEase();

if ( In.IsChecked == true )
easingFunction.EasingMode = EasingMode.EaseIn;
if ( Out.IsChecked == true )
easingFunction.EasingMode = EasingMode.EaseOut;
if ( InOut.IsChecked == true )
easingFunction.EasingMode = EasingMode.EaseInOut;

theAnimation.EasingFunction = easingFunction;
myStoryboard.Begin();
}
}
}

That’s it.  Set the easing sub-type, set the mode, assign to theAnimation’s EasingFunction and run the storyboard. Piece of pie.

Exercise for the reader:  Want to take this a step further? Determine which Easing functions would benefit from additional arguments (e.g., number of bounces), add UI to gather the values, and pass them in to the object.

A Twitter App I want

Whose tweets do the people whose tweets I value, value?

That is, this application would help me find the people whose tweets I consistently value, and then find out whose tweets they consistently value, and it would do it in a reasonably anonymous way. (One can immediately imagine extending this to news groups and then books, music….)

[This RFC is the result of brief musings with John Papa who is not responsible for my corruption of it, but who is a great person to bounce ideas off of]

The Client

Here’s how it works… a client (Windows, Mac, Phone, iPhone, etc.) is created that lets me rank tweets on a scale of –3 to +3, with an unranked tweet scoring 0.

 

 

These ratings are sent to a web service where they are tied to my username but it is not possible for anyone but me to find out my rankings. (I might use my own rankings for culling my lists, discovering that there are people I follow whose tweets I don’t value very much).

Finding People To Follow

The next step is that I can ask the system for the top N valued by my top X.  The restriction is that both N and X must be a multiple of 5. That is, I can ask the system for the top 10 valued by my top 20.  The system will then examine the rankings of my top 20 and combine them to create a list of the 10 names most highly valued by those 20.

It will then return something like this:

Your top twenty ranked the following people in their top ten. They are not in order,  but they are shown as the top 5 and the second 5.

 

Friendly Name @Name # Tweets last 3 months Halves
George @GeorgeW 238 1
JohnA @JohnAdams 12 1
Tom @TJefferson 40 1
JQ @JohnQ 10 1
AJ @AndrewJ 2 1
JMonroe @JamesM 38 2
MVB @MartinVanB 32 2
JT @JohnTaylor 45 2
Millie @MillardF 101 2
Bucky @JamesB 23 2

 

This indicates that overall your top twenty found all of these ten to be in their most highly ranked group, but the group in the first half were ranked more highly than the group in the second half. If you ask for 10 that may not matter much, but if you ask for 50, having 10 groups of 5 can be a good compromise between the false precision of an ordered list and a totally random grouping.

If no one builds this by the time I finish ViKi perhaps this will make a good 2nd project.

Posted by jesseliberty | 1 comment(s)
Filed under: ,

The State of the ViKi

In my previous posting about the VideoWiki project I mentioned that I fell off the edge of the world when I tried to replicate the work I had done previously with the player emitted by Encoder.  I’m told by the team that this is very much a work in progress, so I don’t want to get bogged down in the details, but let’s take a look at some of the issues that came up and where the code sits today.

The version of Expression Encoder that I used (version 2 service pack 1, version 2.1.1216.0) created the Template solution which in turn contained four projects

Microsoft Visual Studio Solution File, Format Version 10.00
# Visual Studio 2008
Project("{<GUID>}") = "Template", "Template.csproj", "{<GUID>}"
EndProject
Project("{<GUID>}") = "MediaPlayer", "MediaPlayer\MediaPlayer.csproj", "{<GUID>}"
EndProject
Project("{<GUID>}") = "AdaptiveStreaming", "AdaptiveStreaming\AdaptiveStreaming.csproj", "{<GUID>}"
EndProject
Project("{<GUID>}") = "ExpressionPlayer", "ExpressionPlayer\ExpressionPlayer.csproj", "{<GUID>}"
EndProject

Our working project on the other hand, is, for now,  a single project solution named Viki-Start) consisting of MainPage.xaml/.cs, App.xaml/.cs and a Views directory with the default three pair of files: AboutPage.xml/.cs, ErrorWindow.xaml/.cs and HomePage.xaml/.cs as well as the usual Properties, Resources, Bin, etc. folders.

Having templated ExpressionPlayer in Blend, we copy ExpressionPlayer.dll, MediaPlayer.dll and AdaptiveStreaming.dll into the bin/debug folder of Viki-Start and add them to the references of the project and we update App.xaml in Viki-start with the template that we created in blend (that is, in Template/App.xaml) being careful about namespaces.

What You Think You Did and What You Really Did

Twenty years ago I learned a good bit of close up magic. What I really liked about it was showing a trick and then listening to the person I showed it to describe what I did to someone else. What they saw was not what I did.  For the past three days, I’ve been insisting to everyone, including myself, that in all the previous videos and tutorials, it worked perfectly fine to call MediaPlayer from within my project but now it changed with Silverlight 3. Wrong!  Going back to find the original code so that I could point out the differences, there are none. Looking at the tutorial and the videos closely, I always launched the project from the html file – which worked then and works now; it is just that now I no longer want to do that; I want to launch from within the program.

What changed was not the ExchangePlayer (well, actually, it did change, but not in a way that affects this discussion) but my requirements.  This is a lesson I have to keep learning: synchronicity is the bane of debugging. It is the error of post-hoc ergo prompter hoc (just because it broke after I moved to Silverlight 3 doesn’t mean the failure had anything to do with moving to Silverlight 3.).

My Current Hack

Sometimes, even if you know you will eventually throw it away, it is worth getting the code to work; if only to understand it in pieces. Here is how I got my code to work.  When you ask encoder to create your starter application (which you’ll remember we then templated in Blend) it emits an entire project as shown above (Template.sln).  The two files we most care about are ExpressionPlayerControl.cs and MediaPlayer.cs.

ExpressionPlayerControl is the control that we are actually templating.  Its job is to display our media clip and raise an event when our markers are hit and it does so by inheriting from MediaPlayer and by creating a custom media stream source for adaptive streaming.  In fact, the point of ExpressionPlayerControl is to extend the MediaPlayer to fully support Adaptive Streaming.

OnStartup

The idiom for feeding the source videos to a MediaPlayer (or an ExpressionPlayer) is to call OnStartup passing in the event arguments obtained from the html page that invoked the program.  Assumptions are made. For example, the initial URI is created by obtaining the URI of the html page.

Uri uriStockContent = HtmlPage.Document.DocumentUri;

That value is then modified if there is a play list (which in my case there always was) in this section

if (e.InitParams.TryGetValue("playlist", out strInitValue))
{
try
{
Playlist.Clear();
Playlist.ParseXml(HtmlPage.Document.DocumentUri, strInitValue);
}

and we’re off to the races.  The supporting code for PlayList is defined in the PlayListCollection class of MediaPLayer and PlayList itself is a dependency property defined to be of type PlayListCollection.

A key assumption built into MediaPlayer is that ParseXml expects a document to serve as the source URI of the media items – that is, the physical location of the document must be the same as the physical location of the videos.

 

When Is A MediaPlayer Not A MediaPlayer?

If you look  up ParseXml in the Silverlight documentation for MediaPlayer you won’t find it. That is because the MediaPlayer that is listed in the documentation is not a Silverlight control, it is, rather, a player to run media using Silveright in an ASP.NET Web Page and is not the MediaPlayer emitted by Encoder.  Same name, different beast. 

My Temporary WorkAround

To get the application up and running for now, I overloaded OnStartup in ExpressionPlayer and in MediaPlayer and then copied the modified DLLs (along with the unmodified DLL for AdaptiveStreaming) into Viki-Start.

  // ExpressionPlayer 
public void OnStartup()
{
base.OnStartup();
Uri whereAmI = HtmlPage.Document.DocumentUri;
string pathAsString = whereAmI.ToString();
int offset = pathAsString.IndexOf( "TestPage.html" );
string stub = pathAsString.Substring( 0, offset );
Playlist.Clear();
PlaylistItem pli = new PlaylistItem();
pli.MediaUrl = new Uri( stub + "/encoded.wmv" );
pli.IsAdaptiveStreaming = false;
pli.ThumbSource = stub + "/test.jpg";
pli.Title = "Encoded Video";
pli.Description = "Hardcoded Hypervideo";
Playlist.Add( pli );
}
// MediaPlayer
public virtual void OnStartup()
{
Playlist.Clear();
m_autoPlayCache = true;
m_autoLoadCache = true;
m_mutedCache = false;
m_stretchMode = Stretch.None;
UserBackgroundColor = new SolidColorBrush( ColorFromString( "#FF0000FF" ) );
DisplayTimeCode = false;
CaptionsVisibility = Visibility.Collapsed;
}

 

Not beautiful, but sufficient to keep the project moving.

     Previous  ViKi Version 0.0.01
 

 

Making a good posting GREAT

 

An example of the difference between an “ok”  blog post and a brilliant posting  crossed my reader yesterday and it was too canonical not to comment on. 

Scott Hanselman wrote about his wish (shared by so many of us) for a way to signal to tech support that we’re clued in, without sounding obnoxious.  

In short, his suggestion is that you say a magic word (“fizzbin”) as a signal that you know what you are talking about thus saving everyone a lot of time.

My point however, is that his article can be used as an object lesson in what makes a good post great, and, fortuitously, you can see the difference in this case by drawing a line where a competent blogger might have stopped writing. Had he done so, Scott woud have had a perfectly respectable posting, but by adding a short dialog, his posting went from “ok” to instant classsic. Here is a brief excerpt:

Fizzbin

(This image is cropped and the red was added by me)

Click here for the full postin.

I believe that it is the dialog, and especially the geek-familiarity Scott implies with the final line ("sweet!")  that really nails it.

 

Great post.

 

Posted by jesseliberty | with no comments
Filed under: ,

ViKi Version 0.0.01

It is of course inertia, that overwhelming sense of “what is the most important thing to do first?” that will kill you, and this project got hit bad because it came just when Passover interrupted my normal schedule, along with the usual slew of unusual events, such as preparing for TechEd (ah, I’ve another month, what, me worry?)

So, believing strongly that the first thing to do is something I’m going to take my own advice and start building; not where the most important lessons are, but where the low hanging fruit is: by creating a hyperVideo application in Silverlight 3 that will accomplish the following:

  • Get something going
  • Force the issue of where this project lives and how I track the code
  • Give me something concrete to improve
  • Start us right off with media
  • Force the issue of how does a user even follow this project without Silverlight 3 installed (I think I have a good answer for that)

How Do You Follow This Tutorial If You Don’t Have Silverlight 3?

hourglassOfProgrammersLet me be clear, Microsoft’s position  is that Silverlight 3 is a developer only product, currently in Beta with no announced release date. Thus,  we will continue to support and to provide lots of learning material for Silverlight 2.  That said, this site in general and my blog in particular seems to attract an hourglass shaped demographic

Thus, I feel fairly safe assuming that a large proportion of readers of this blog have (or will soon have) set up a computer with a Silverlight 3 development environment. That said, I will try to put in images as well as live streaming examples so that you can follow this project even if you do not yet have a computer or virtual machine with Silverlight 3 installed.

 

 

Version 0.0.01

 

Nothing gets me started like starting. I opened a new project and chose Silverlight Navigation Application from the Templates section and C# from the Project types

 

While I believe in being bi-lingual C# and VB, I usually start in C# if given the opportunity. I will provide VB code for this entire project, however, either translations of tricky parts, or complete working code periodically.

 

This opened a very pretty navigation page which I proceeded to make ugly by opening Blend 3 and modifying in a few ways (changing the BrandingTextNormalStyle, BrandingTextHighlightStyle adnd  the PageLink style as well as the border margins and sizes, to suit my personal aesthetics

Modified Navigation Styles

PageSwitchingThis will serve as the framework in which we will build the ViKi player, instantly rendering my videos on multi-page applications quaintly obsolete.

 HyperVideoPart1

 

 

The key to getting started with the ViKi project, however, lies with a different set of videos; the 3 part series that begins here  and which we will adapt as the starting point for the ViKi.

 

 

 

 

The First Thing We Need Is A Video

It would be helpful if we were all looking at the same video, and it would be even more helpful if that video was

  • short so that we don’t have to shlep around inside a huge file and
  • about a topic that we won’t confuse with the ViKi project itself

I am going to download Element to Element Binding because it is just under 6 minutes and has nothing to do with Hypervideo.  Since I want to have a marker every 20 seconds, (a somewhat arbitrary decision) this video will end up with about 18 markers.  I chose every 20 seconds as I see that as being about the right compromise between having as many opportunities for markers as possible without exceeding human reaction time.

To create this for yourself, download the video, place it into encoder, put a marker at 20 seconds and every 20 seconds after (naming each marker sequentially (marker-01, marker-02, etc.) and then instruct Encoder to give you a Silverlight Standard player as discussed in the Hypervideo videos!

 

Encoding

The image has been cropped, but you can see that we’ve placed a marker every 20 seconds and named them sequentially from Marker1 to Marker 21.

Emitting The Player

 

With the video and markers in place, it is time to ask Encoder to emit a player for us (far easier than creating one by hand!). To do so, click on the OutputTab (not shown in illustration above), choose the Silverlight 2 Default template and modify the output name to add the word Encoded as shown below,

EncoderOutputForHypervideo

 

 

 

Click on the encode button at the bottom of Encoder, and just a few moments later you not only have an encoded video, but much more impressively you have a player ready to display your new hypervideo.

(All of this is reviewed in great detail in the 3 videos and the series of blog entries on Hypervideo  that begin here – we’re really just catching up here as a starting point on the ViKi project). 

As you may remember, the next step is to click on the white dot next to the template name and ask to edit the project in Blend, where you will name your new template, build the project and then edit the a copy of the player template (please see the referenced blog entries for step by step directions)

After you save the template in Blend, return to encoder, encode the video and return to your new project. Copy the styles from the app.xaml from the encoded project into the app.xaml for your new project (combining them). 

Then copy MediaPlayer.dll and ExpressionPlayer.dll from the Encoder-emitted player project into the bin/debug directory of your new project.  Add a reference to each in your project and then add a namespace to the top of your HomePage.xaml,

xmlns:ExpressionPlayer="clr-namespace:ExpressionMediaPlayer;assembly=ExpressionPlayer"

 

The Home Page

We’ll place the player inside the Home page much as we placed in inside page.xaml in the previous examples,

<navigation:Page x:Class="ViKi_0._0._01.HomePage" 
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:navigation="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navigation"
xmlns:ExpressionPlayer="clr-namespace:ExpressionMediaPlayer;assembly=ExpressionPlayer"
Title="HomePage Page">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="9*" />
<RowDefinition Height="0.5*" />
</Grid.RowDefinitions>
<ExpressionPlayer:ExpressionPlayer
Margin="0,0,0,0"
x:Name="myPlayer"
Style="{StaticResource ExpressionPlayerStyle1}"
Grid.Row="0" />
<TextBlock x:Name="Message"
Grid.Row="1" />
</Grid>
</navigation:Page>

Falling off the Rails

It was about here that I fell off the rails.  I thought  I’d grab the code that I’d written and demonstrated a dozen times and just plunk it down into the home page. “not so fast” the gods yelled. I then spent 14 hours looking at (a) how ExpressionPlayer had changed and why it worked perfectly when its parameters were passed from an html file but not at all when they were passed from my code.

I spent a good part of the next day getting it to work, and along the way learning a good bit about how the code emitted by encoder has changed (for the better) and why, and what it means to working with that code. I also learned a good bit about working with URIs, media and all sorts of digressions that will come in handy. I will write that story tomorrow.

The following 2 severely cropped images will give a sense of the working code as it stands today,

 ViKi0001.1
The “home” page with the templated and modified Expression player playing the hypervideo we encoded and responding to the marker at 20 seconds.

 

ViKi0001.2

   The about page with an accordion from the Toolkit serving to provide information about the project.

 

All the code and a detailed walkthrough to follow.

 

  Previous: VideoWikiDesign Step 1      Next State of the project
 
 
 
 






Powered by VisualSVN!

VideoWiki Design Step 1

 

The initial approach to designing the VideoWiki is to layout all the obvious pieces of the design, understanding that this will evolve over time.  Here is my first cut at the design.  

If you have Silverlight 3 installed, the following is the live interactive outline, otherwise, below is a snapshot of the outline as an image,

OutlineImage1 OutlineImage2 OutlineImage3

While this lays out the topics I hope to cover in the next six months or so, it says nothing about schedule, or how to illustrate these topics or even how these topics relate directly to the VideoWiki (with some obvious exceptions. But it is a start; it is, to harken back to yesterday's analogy, stimulus applied to overcome the axon hillock.

 

                                      Previous VideoWiki Step 0   Next Version 0.0.01

Posted by jesseliberty | 10 comment(s)
Filed under: ,

VideoWiki - Step 0

 

The neurons in your brain have a basic structure of an axon (the finer cable like projections) and dendrites (the branches) and the soma (the central part of the neuron).  The axon emerges from the soma at the axon hillock where there is the greatest density of voltage dependent sodium channels. The interesting thing about a neuron is that it is an "all or none" mechanism – that is, like the binary underpinnings of computing, either it fires or it doesn't.  The interesting thing about the axon hillock is that the action potential has to build quite a bit before you overcome the threshold for that neuron to fire. The action potential builds by other neurons stimulating it and it is the most easily excited part of the neuron. Yet, it is almost as if there is a built in resistance to firing, the hillock acts as a guard against impetuous firing, but once that resistance is overcome… zap!

I am very much like that when it comes to starting a project. I  have an enormous metaphorical axon hillock that stands in the way of getting going, and a great deal of stimulation from half baked ideas is required before I finally fire. I'm not intimidated by a blank sheet of paper (in fact, that is my favorite starting point) but I like to let lots of ideas cook for a while before I choose my path (each time I do I can hear doors closing and gates slamming on all the paths I didn't take).

 Chain Reaction

Keeping The Chain Reaction Alive



For a nuclear bomb to work there must be chain reaction in which one reaction causes an average of more than one additional reaction so that there is a rapid (literal) explosion of reactions. 

All of this happens very quickly, and one anecdote I particularly like from Richard Rhodes' brilliant book The Making of the Atomic Bomb  is that the time criticality for the necessary nuclear reaction at Los Alomos was found to be 30 nanoseconds, and so he coined the term shake to mean 10 nanoseconds, thus criticality was three shakes (of a lambs tail).

But I digress. The analogy here is that early in the fission reaction it is fairly easy for the chain reaction to stop if there is not enough propagation of reactions, just as early in a design/development process it is easy for the project to become shelved through becoming either distracted by something else or stymied by indecision.

 

Keep Moving

The solution, especially at this critical phase, is to keep moving, letting one piece of the project create other pieces and overcoming obstacles by force of will and by momentum. Thus, I will make it my business to create blog entries (and soon videos and more) that address this project with great frequency, especially early in the project.


Project Challenges

My greatest challenges right now are

  1. Organizing the parts of the project
  2. Creating a starting schedule
  3. Matching the project to the only partially related goals of demonstrating Silverlight 3 features
  4. Making sure that the VideoWiki project and my other projects (this blog, twitter, videos, tutorials and the new book) all leverage (but do not duplicate) one another or there is no prayer of getting it all done.

To do this I have to take a number of risks and the top three are:

  1. Publishing a set of tasks that I know will change over time
  2. Publishing a schedule that will change over time
  3. Writing code for the project before anything is certain ("you start coding, I'll go get the spec.")

The next related blog entry will have my preliminary task list (posted later today or tomorrow)

 

      Previous: The VideoWiki Project                                     Next  VideoWiki Step 1

Designer TinyUrls

It turns out, as many of us have known but not really focused on, that you can ask TinyURL.com to give you a custom url if it is not otherwise taken. We know what has happened with full URLS, and we know (according to their management) that TinyURLs never expire. Since a custom tinyURL is easier to remember (it is easier to remember that my blog is at http://www.tinyurl.com/JLBlog than it is to remember that it is at http://www.tinyurl.com/cqla8s 

CustomTinyURL

Thus, I predict, with some confidence that having a custom URL will become valued, and then scarce, and then valuable.

Not wanting to being either left out or piggish, I've scoffed up a few I'd like to have before the (self-fulfilling prophesy induced?) rush:

http://www.tinyurl.com/JLBlog   - links to my blog

http://www.tinyurl.com/SLGeek  - links to my blog

http://www.tinyurl.com/VideoWiki  - links to the entry point on my new project on VideoWickis

http://www.tinyurl.com/JLTwitter – links to my Twitter home page

http://www.tinyurl.com/JLPersonal – links to my personal blog and LiveSpace

http://www.tinyurl.com/JLBooks – links to my reading list

http://www.tinyurl.com/JLReviews – links to my reviews page

 

There Ain't Nothin' Like A Domain

Lots of things in life are beautiful, but brother,
There is one particular thing that is nothin' whatsoever
In any way, shape or form like any other.
There is nothin' like a domain,
Nothin' in the world,
There is nothin' you can name
That is anythin' like a domain!

-- South Pacific (more or less)

 

On a somewhat related note, GoDaddy.com has some incredibly inexpensive domains if you are willing to settle for funky extensions like .info or if you don't watch carefully as they assemble your shopping cart!

Thus, I bought up http://www.ExampleCodeQuality.info (which links to the page explaining the idea) and http://www.VideoWiki.info which points to the first page in the new VideoWiki project.


This work is licensed under a Creative Commons Attribution By license.
Posted by jesseliberty | with no comments
Filed under: ,

VideoWiki – A Open-Book Design-To-Delivery Silverlight 3 Project

VideoWiki Project and Meta-Project – Launch

I am pleased to announce a new long term project that I am launching here on Silverlight.net, principally on my blog, but that will reach into my videos and beyond.

This note is the entry point to the project; whenever you are joining us, this is the place to start.

In this note,  I will provide the initial goals and the general approach.

A Project and a Meta-Project

The Project is to build a meaningful, useful, exciting application in Silverlight 3, from design to delivery, demonstrating a wide range of Silverlight techniques, best practices, and more.

The Meta-project is to demonstrate and document this entire process as openly as possible;  maintaining a running commentary on the project and documenting the process and the lessons learned, including design, meetings, new techniques,  mistakes, victories, changes in direction, improvements, distractions, and all the other issues that arise.

Keeping Your Eyes On The Prize

The Motto of this project, which will appear frequently is this:

The VideoWiki Project:  Our Goal Is not to create a great product, our goal is to create great programmers.

This key distinction will drive some potentially controversial decisions along the way (e.g., to stub out some areas that might be important in a final product but are not immediately relevant to learning something new).

It happens that I believe what I want to build is exciting and interesting enough that it may make sense to bring all the way to completion, in this forum or another; but that is not the proximate goal this effort.  That said, the closer we stay to a spec-driven real-world scenario, the more valuable the experience will be.

The VideoWiki Project

We will be building what we believe to be the world’s first VideoWiki.  A VideoWiki allows you to associate keywords with every moment of a video, and links with every keyword. More, a VideoWiki allows you to have multiple sets of such associations, built by different sets of people and targeted at different audiences.

VideoWiki

We start with Hyper-video: Imagine that you are watching one of our videos and as you watch, a list of all the topics being mentioned is scrolling by in an adjoining window. If you click on a topic ,the video pauses while a list of links appears in a new window. Click on a link and you are taken to related videos or blog entries or tutorials for additional information.  

Extending Hyper-Video to the VideoWiki

The markers will be added at run time. The links will be loosely coupled to the markers. This flexibility means that a given video can have more than one set of markers, and a given set of markers can have more than one set of links.  For now, I've coined the word Wick for the combination of a set of markers with a set of links, and the key difference between hyper-video and a videoWiki is that anyone can create a Wick for any Video. Over time, Wicks might be differentiated in any number of ways:

  • Targeted at skill level
  • Targeted at domain (animation for game programmers vs. animation for business programmers)
  • Good Wick creation is a skill and an art, some Wick creators might have a following

Successive Approximation

I will approach the creation of the VideoWiki project from the “get it working and keep it working” school of programming,  with an eye on finding those aspects of the project that are most likely to bring out interesting aspects of RIA in general, and Silverlight 3 in particular.

In the short term at least, some areas will be fully developed, others will be stubbed out and only returned to if the project’s momentum carries us there.  Similarly, depending on the availability of people with certain skills (most especially the availability of folks from the Expression group) we will explore various areas as opportunities arise (I have a couple guest collaborators lined up who will add great value as we go).

High Priority Areas.

Among the skills and techniques that I hope to demonstrate in the first few months are:

  • Silverlight 3 Layout controls
  • Media Player, Expression Encoder, Markers, Injection
  • Rich controls and new  Silverlight Toolkit controls
  • Animation (both storyboard and procedural) and the Silverlight Layout System
  • Out of Browser Experience
  • Data Validation
  • Templating, and the VSM
  • Custom controls, Dependency properties and the States and Parts model
  • Effects, Pixel Shading, 3-D, 3-D Animation, PlaneProjections
  • Save file and Isolated Storage
  • Messaging
  • Various new Data techniques including aspects of the Entity Framework and Data Services

A Special Role for How-Do-I Videos

A key feature on our site is the rapidly growing set of How Do I videos that typically run about 20 minutes and cover a specific topic in either a single video or a short set of 2-3 videos. I will incorporate videos into this project, but in a way that has not been attempted before: creating videos that work both as stand-alone single-topic videos and as illustrations for the project. 

Done properly, readers who are following the project should find the videos to be an integral part of the documentation, and users who are not following the project should find the videos stand on their own with no need to be aware of any aspect of the project at all. That is the theory, but as my old boss, Pat Johnson used to say: "In theory, theory and practice are the same, but in practice they never are."

Following (and ignoring)  the Project in my blog

The dual nature of the videos will be brought into my blog so that those who are interested can follow along easily and those who are not interested in the project can find the information they want without feeling that the project has "taken over."

I’ll do this not by segregating the project but by by adding two links in the sidebar: VideoWiki Start (which will bring you to this entry ) and Videowicki Latest which will bring you to the latest entry in the project

and by leveraging two innovations; one already in place, and one new.  

Each entry will have Next and Previous links, so that those who want to follow the project can thread their way through to the related messages easily.

 

 

Dual Purpose Mini-Tutorials

Much as the videos will be called upon to serve both those following the project and those who are not, so will the project's mini-tutorials. To accomplish this, I'll divide each of these into three easily distinguished parts:

Part I – Project Motivation– What we’re up to, what our goal is, how what we’re about to do fits into the project

Part II Tutorial – A stand alone mini-tutorial on a useful Silverlight skill that one can read without following the project (an example of what I mean by a mini-tutorial can be found here and here, though these were not part of the project).

Part III Project Integration - fitting what was shown in the tutorial  into the project

(Not every entry will be this rigid, but you can see that my goal is that, as with the videos, the blog entries can stand on their own for those who are not following the project.)

Frequency

While I don’t want to lock myself into a specific schedule,  if this project is going to maintain its momentum I would expect that Project-related entries will be fairly frequent. That said, there are many other topics to blog about and flexibility will be essential.

Participating

I can imagine some developers wanting to participate in this in various ways.  Let me start by saying that I’m eager for feedback, suggestions and constructive criticism at all times and will read these promptly and respond as diligently as I can.

That said, just reviewing code suggestions and submissions can quickly become a full time job, and I don’t envision this as an open-source project (I simply don’t have the bandwidth to manage that).  As the project evolves, I can imagine that some folks might want to take on implementing some part of it, and I look forward to figuring out how to make that work.

Next Steps

Rather than risk being caught in design paralysis, look for an entry very soon that implements one or more small parts of this project. I’m a big believer in overcoming the high resistance to new projects by building something. I understand the value of design, and the risk of coding yourself into a corner, but I also know the risks of too much hand-wringing, and, especially in this case, I will almost certainly err o the side of "build it to throw it away" rather than "measure twice, cut once."

On a personal note, this is a project I've been thinking about for a very long time; it is the first major addition to my efforts as Silverlight Geek in a while and I'm quite excited about it. But it is an experiment: if it meets the needs of the community, then we'll build on it; if not, then we'll kill it and try something else. For now, I look forward to the opportunity this affords to tackle larger and more complex problems within a more realistic context.



                                                   Next: Step 0


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

The New Microsoft Mouse

I had a little trouble unpacking my new mouse

 

arc

 

But once I did, I really like it. Very comfortable and very nice looking. (no wise cracks about looking for the apple logo, thank you).  I'm impressed by the willingness of Microsoft to do this; and very pleased. Now, if we can get a package I can open without a box cutter and a machete….


This work is licensed under a Creative Commons Attribution By license.
Posted by jesseliberty | 10 comment(s)
Filed under:

Why DataBinding With ComboBoxes is NonTrivial

…and Why Coding Is So Much Fun

iStock_BoyWithBrainXSmall A Gonzo Adventure In What You Can Learn When You’re Not Doing What You Are Supposed To Be Doing And You’ll Be Done In Just A Minute, It Almost Works

 

[Read the VB version of this post here

 

 

 

Two days ago I thought I was late getting the code done for my latest tutorial (it turns out that I was actually early but that is a different saga).  I got up early and swallowed lots of pills and drank lots of coffee and took a short nap and then came into the office and sat down at the computer and said, “OK, I just need 20 pages on 3d in Silverlight 3; piece of cake. But anyone can write a tutorial on 3d, what I want to do is show how it fits into writing something real. It isn’t just a toy for little kids, this thing has sharp edges, a person could hurt themselves, we want to put this in context…”

Now, the coolest use of 3d I happened to have seen in the last six or seven minutes was a free program that gets the lyrics for whatever you’re listening to. Its entire UI (or UX as we RIA cognoscenti call it)  is a panel about 400 x 600 pixels. This is nearly entirely filled with scrollable lyrics but there are a couple small icons, including, in the lower left hand corner, a very attractive italicized “i”

If you hover over that seductive little i, it lights up invitingly. Click on the i and hey! voila! the panel rotates 180 degrees revealing its “back” where you can find settings and other cool stuff that you don’t need every day but is very handy to have easily available.

When you finish playing with the settings and have put back all the things you broke, you click and the panel rotates back.  Perfect.  Useful, elegant, space saving and classy.  I want one. More urgent:  I want to build one.

Zo!  That is the next tutorial, but that is not what I’m writing about here.

What I’m writing about here is what happened when I set out to build one, that I did not intend, and was not part of the project and I had no business spending time on. it was long ago and far away….

I had chosen to make my panel databound, and because I was listening to music at the time I was writing the code, I decided that the cards would provide basic information about a musician on the front, and the musician’s bio on the back.

To insinuate a tenuous business connection I created an Employee class to hold all this information (who knows, maybe these guys work for my record company?), and I used the same fields you would (more or less):

public string FullName { get; set; }
public string NickName { get; set; }
public DateTime Birthdate { get; set; }
public string Locality { get; set; }
public string Phone1 { get; set; }
public int Phone1Location { get; set; }
public string Phone2 { get; set; }
public int Phone2Location { get; set; }
public string JobTitle { get; set; }
public string JobNickName { get; set; }
public double JobLevel { get; set; }
public string Salary { get; set; }
public string Performance { get; set; }
public string Bio { get; set; }

Now, this was certainly not the final set of properties, and there was much to fix, but as I created the UI for the phone numbers, it was blazingly clear to me that I wanted the phone type to be in a combo box

ComboBox

That was when the trouble began.  When you chose a new artist all the fields changed…. except the Phone Location (cell, home, etc.)

The more I looked at it the more baffled I became. Set aside that the code was a quick hack with insufficient decoupling of UI from data, it didn’t even work.

After a while this became the night’s obsession, culminating in my doing what I always tell others to do but never quite get around to doing myself: write a tiny program that demonstrates the problem in isolation and ask for help.

Thus was born: ComboBoxProblem.xaml

   <UserControl x:Class="ShowTheProblem.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="400" Height="300">
   <StackPanel x:Name="mySP">
      <TextBlock x:Name="Phone"
                 Height="20"
                 VerticalAlignment="Bottom"
                 Text="{ Binding Phone, Mode=OneWay }" />
      <ComboBox x:Name="PhoneType"
                HorizontalAlignment="Left"
                Width="100"
                VerticalAlignment="Bottom"
                SelectedIndex="{Binding PhoneLocationID, Mode=OneWay}"
                ItemsSource="{Binding}">
         <ComboBox.ItemTemplate>
            <DataTemplate>
               <TextBlock x:Name="PhoneTypeItem"
                          Text="{Binding Location}" />
            </DataTemplate>
         </ComboBox.ItemTemplate>
      </ComboBox>
      <Button x:Name="mybutton"
              Content="Press Me"
              Margin="10" />
   </StackPanel>
</UserControl>

I’ll spare you the supporting code (I hate showing broken code) but I posted this on an internal list and immediately got back two interesting answers: there’s a bug in combo box (there isn’t) and if you set the Mode to TwoWay instead of OneWay everything works.

The Great White Whale

Now I know a Great White Whale when I see one, so call me Ishmael and I was off, spending much of the rest of the night trying to figure this out, and realizing as I went that I truly hated the fact that the Person object  had to know so much about the phone location collection that populated the ComboBox.

It turns out that there were a number of interlocking problems here. Mike Hillberg (a Principal Architect at Microsoft) pointed out that with one-way binding as soon as the control changes SelectedItem, the binding is replaced with the new value.  He also pointed out that I/we were having the person’s GetPhoneLocation return new objects, and just because two objects have locations set to the same string (e.g., “Home”) doesn’t mean the two references point to the same object in memory. (yes, yes, but by then it was very late).

His excellent blog post got me most of the way towards where I needed to go, but I rebelled at the idea of imposing WPF semantics on Silverlight, and I really wanted to constrain the values so that they were self-identifying; that is I wanted more of an enumeration than a class.

Another Microsoftie offered his solution, which I liked very much but his approach included the assumption that the person object would contain an ID that was an offset into the collection of phone numbers used to populate the combo box. That was where I choked.

How To Make An Enumeration Behave Like A Collection

What I wanted was to use an enumeration, with all the wonderful Intellisense support and the intuitive scoping it provides. But you can’t hand an enumeration to the ItemsSource property of a comboBox, nor can you treat enumerations as strings (at least, not without a little work).

After a bit of tinkering, (and then a little hammering, followed by some smashing and yelling)  the solution that finally caught the leviathan (though I’m afraid ol’ Starbuck was never seen again)  was this:   

  1. Create a class that represents one location (so that you can have a collection of said locations, so that each member of the combobox can be an instance of that class).
  2. Obtain the enumeration semantics by giving the class a single member that is an enumerated constant.
public enum PhoneLocationEnum
{
Home,
Office,
Cell,
Other
};
public class PhoneLocation
{
public PhoneLocationEnum Location { get; set; }
}

 

You can now create a collection of these, initializing them with full support from Intellisense,

PhoneLocation2 

I’m so happy.

But I need an ItemsSource

What we need is an observable collection to serve as the ItemsSource for the comboBox. We’d like to add each of the PhoneLocation objects to that collection, but where will that collection live?  What we really need is a class that is a collection of Phone Location objects. Aha!

public class PhoneLocations : ObservableCollection<PhoneLocation>

This sneaky bit of C# makes PhoneLocations a kind of or derived type of Observable collection of PhoneLocaitons and as such fully legal as an ItemsSource. To wire it up I need to create a namespace (local) that points to this assembly and then declare this puppy in the resources section of the Xaml file,

<UserControl.Resources>
<local:PhoneLocations x:Key="phoneLocations"/>

[ Thank you Hamid Mahmood for showing me this bit of Xaml ]

Now, finally, I can put the pieces together, Here is the Xaml

<UserControl x:Class="ComboBoxSample.Page"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ComboBoxSample"
Width="400" Height="300"
Loaded="UserControl_Loaded">
<UserControl.Resources>
<local:PhoneLocations x:Key="phoneLocations"/>
<local:EnumToStringConverter x:Key="converter" />
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="White">
<StackPanel x:Name="mySP" Margin="20">
<TextBlock x:Name="Phone"
Height="20"
VerticalAlignment="Bottom"
Text="{ Binding Phone, Mode=OneWay}" />
<ComboBox x:Name="PhoneType"
HorizontalAlignment="Left" Width="100"
VerticalAlignment="Bottom"
ItemsSource="{StaticResource phoneLocations}"
SelectedItem="{Binding PhoneLocVal,
Mode=TwoWay,
Converter={StaticResource converter},
ConverterParameter={StaticResource phoneLocations}}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Location}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<Button x:Name="mybutton"
Content="Click Me" />
</StackPanel>
</Grid>
</UserControl>

ComboBox has three important binding-related statements:

  1. The ItemsSource is bound to the phoneLocations that was defined in the resources and thus tied to the observable collection of PhoneLocation objects

  2. The SelectedItem is bound to PhoneLocVal which as you’ll see in a moment is the integer value stored in Person that is directly derived from the enumerated constant for the phone location

  3. The DataTemplate is bound to Location which is the (only) property of the PhoneLocation object and which is of type PhoneLocationEnum

This last point is critical.  At the risk of repeating; we declare the enumeration, then we declare a PhoneLocation class that has a single member whose type is that enumeration, and finally we declare a class that is an observable collection of those objects whose member is of the enumerated type!

Type Conversion

There is a second statement in the resources section of the Xaml that I’ve glided right past,

<local:EnumToStringConverter x:Key="converter" />

This declares a type converter, and we see it invoked in the ComboBox 

SelectedItem="{Binding PhoneLocVal, 
Mode=TwoWay,
Converter={StaticResource converter},
ConverterParameter={StaticResource phoneLocations}}" >

In this declaration we are saying that while we are binding to the PhoneLocVal property we don’t expect to know how to display that, and so we’ll need to use the declared converter and, further, we’ll pass in the phoneLocations as a parameter.

The code for the conversion implements IValueConverter, and thus has two methods: Convert and ConvertBack:

public class EnumToStringConverter : IValueConverter
{
public object Convert(
object value,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture )
{
int phoneLocationAsInteger = (int)value; ;
PhoneLocations locations = parameter as PhoneLocations;
if (locations != null)
{
foreach (PhoneLocation pl in locations)
{
if ((int)pl.Location == phoneLocationAsInteger)
return pl;
}
}
return null;

}

public object ConvertBack(
object value,
Type targetType,
object parameter,
System.Globalization.CultureInfo culture )
{
throw new NotImplementedException();
}

}

We cast the value we’re given to an integer and the pareameter to a PhoneLocations collection. We then iterate through the collection checking to see if we find a member whose Location when cast to an int is equal to the value we were given. If so, we have our winner, and we return it.  This converts an integer value to a Phone Location while ensuring that we stay within the boundaries of the enumerated constants.

Once I had that, I could sleep.

The complete source code is available here.

womc100

This code was built with Silverlight 3 Beta.

Keeping you informed, and reducing confusion

 

Guaranteed to have the quality of Example Code - Every Time 

WOMC

To keep things a bit tidier here, I've consolidated the messages about the Example-Code Quality effort to provide development environment information to a  centralized page that can also be reached through http://ExampleCodeQuality.info

Thanks for your ongoing support 

 

Posted by jesseliberty | with no comments
Filed under: