Jesse Liberty - Silverlight Geek Page view counter

Behind the Curtain

Our team (officially Community Program Managers, with the secret identity of STO Ninjas) has quietly expanded over the past few StoNinja50 months, including the additions of two amazing and terrific new voices: Pete Brown and Jon Galloway.

Their names are linked to their blogs, which I highly recommend subscribing to.

 

 

 

Syntax Highlighting (Finally) Done Right

This posting, however, is occasioned by Jon writing a post on how to make Syntax Highlighter work with Community Server… no small trick, but Syntax Highlighter now supports hosting (!).    Jon provides all the links you need (including a link to our fearless leader’s extensive post on the topic) , and great instructions,

The key benefit is that the code has syntax highlighting but still support clean copy and paste; something I’ve wanted (and readers have demanded) for a long time.

Here’s an example:

using System;
using System.Collections.Generic;
using System.ComponentModel;


namespace SilverlightHVP.ViewModel
{
   public class ItemsViewModel : INotifyPropertyChanged
   {
      private State state;
      public List<Item> Items
      {
         get { return state.CurrentItems; }
         
      }


      public Item CurrentItem
      {
         get { return state.CurrentItem; }
         set 
         {
            if ( value != null )
            {
               state.CurrentItem = value;
               NotifyPropertyChanged( "CurrentItem" );
            }
         }
      }

      public ItemsViewModel( State state )
      {
         this.state = state;
         this.state.CurrentSetChanged += 
            new State.CurrentSetChangedHandler(state_CurrentSetChanged);
         UpdateItems();
      }

      void state_CurrentSetChanged( object sender, EventArgs e )
      {
         UpdateItems();
      }

      private void UpdateItems()
      {
         NotifyPropertyChanged( "Items" );
      }


      public event PropertyChangedEventHandler PropertyChanged;
      private void NotifyPropertyChanged(string propName)
      {
         if (PropertyChanged != null )
         {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
         }
      }
   }
}

syntax If you are looking at this on line, you should see a very nicely formatted layout with syntax highlighting (see image).  In a stream, however, it is straight html.  Even more valuable, notice the four symbols (circled in red); when you click on the code these appear and offer “show source” (the image has an inlay of the source as it is shown when clicking this). The other three are copy to clipboard, print and help.  Very very nice.

Thanks Jon!

(Click on image for full size)

This work is licensed under a Creative Commons license.

Test Driven Silverlight Body Snatchers

 

MiniTutorialLogo

 SLHvpLogoNoBorderThis posting is part of the Silverlight HyperVideo Platform documentation and a Silverlight Mini-tutorial. The information in this posting, however, should be of interest to anyone writing meaningful Line of Business applications with Silverlight.

[This is the first of two parts on Test Driven Development. Part 2 will walk through creating Unit Tests in “real time”]

 

The premise of the classic 1956 film Invasion of the Body Snatchers is that there are “pod people” among us, who are converting “normal” people into pod people one by one.

 

“Once you are a pod person, you think everyone should be one”

Once you begin seeing the benefits of TDD you tend to evangelize; its working great for you and you want everyone to become one.  This can be helpful, annoying or alarming depending on who you’re talking to.  My daughters, for example, are quite sick of hearing about it.

"They're here already! You're next! You're next!"

It seems reasonable to many developers to create unit tests for their code; but the presumed high cost of doing so implies for waiting for a project that is not in “crunch mode.”  Most developers will be waiting a long, long, long time.

Experience indicates that TDD actually saves time – you spend less time debugging and more time coding. Unfortunately, that sounds like “a good theory” and we all know that In theory, theory and practice are the same,
But in practice, they never are.

The bigger problem is Isaac Newton. Most of us suffer from Newton’s first law (significant inertia) and when confronted with an evangelist, we are governed by his third law (the more you push, the more I push back.)

“Give Up! You Can’t Get Away From Us! We’re Not Going To Hurt You!”

That said, for the past few years I’ve had the nagging sense that I was missing something important.  Especially given that some of the folks I respect most in the industry were strong proponents; not least my mentors in all things good:  RMSquaredF: Robert (Uncle Bob) Martin and Martin Fowler who laid the ground work and established best practices in their seminal works Refactoring: Improving the Design of Existing Code (Fowler) and Clean Code: A Handbook of Agile Software Craftsmanship (Martin).  In the latter book, Robert Martin summarizes his approach which I paraphrase here:

  1. Don’t write production code until you’ve written a failing unit test
  2. Write just enough of a test to fail. 
  3. Write just enough code to pass the test 

What you are aiming for is about a 30 second cycle of write-test, write-code, Run-test.

Uncle Bob’s premise is that you tremendously reduce your risk and thus your fear because your production code never gets ahead of what you know; and you know it because you’ve tested for it.

“I Don’t Want Any Part Of It.” 
“But You’re Forgetting Something….. You Have No Choice.”

 Invasion poster A second premise of folks who evangelize TDD is that you really have no choice; it is a case of “pay me now, or pay me later.” Either you create the unit tests or you spend that much time and a good deal more on debugging. 

The Silverlight HyperVideo Platform project offered the ideal opportunity to take on TDD, and the only way to do so was by Fiat. Thus, I made the executive decision to require unit tests for all code checked into the project (not hard to enforce so far, as at the moment all the code in the project is mine).

 

“The words, the gesture, the tone of voice, everything else is the same, but not the feeling.”

The rules for writing good tests are very similar to writing good code, but with a couple extra requirements.  Stealing again from Robert Martin, here is a paraphrase of the good-test rules developed at his company, Object Mentor:

  • Test must be quick. The slower a test runs the less likely you are to run it.
  • Tests must be independent of one another; any side effects or dependencies must be avoided
  • Tests must be repeatable: running the same test against the same code base must give the same results
  • Tests must return unambiguous results
  • Tests must be isolated from the production code

 

Configuration – ViewModel Objects

I published a plan for configuration that made use of Xaml files. I realized yesterday, in one of those forehead slapping moments, that a design that relies on placing configuration files on the client of course will not work due to access limitations.  No harm done: the Xaml files were just a mechanism for creating the configuration business objects; and there are natural server-side analogs.

We’ll use the Xaml file approach for enabling the user to maintain the state of the program when suspended or shut down (using local storage), post V1.

The working design now looks like this (using a relational database for persisting the configuration information, and WCF-RIA Services for moving the objects to the client. (A forthcoming blog entry will walk through that aspect of the implementation in detail)

slhvpDBTables

(Click on image for full size)

Links Vs Units

Links are a unique identification of a Unit, and Units are not represented by a class. A Unit is a set of Items (and the selected item), each item’s set of topics (and the selected topic) and each item’s set of links (and which links are currently displayed).  Notice that units are identified by a URL.  In V1 the selected item and selected topic are the first in the set, and this design is used only for configuration.

After v1, we’ll move from read-only to read-write, allowing the user to persist the current unit and to recreate the state of the application at a later time.

From Tables To Objects

The diagram above was created to show how the RDB would work, but it is a bit misleading.  What we really want is not tables but rather objects.  There is a very small jump (in this case) from the tables to the business objects as shown here:

TDDObjects 
(Click on image for full size)

There are a number of advantages to creating these objects, the most significant of which is that I can go ahead and implement the configuration without regard to how these objects were created, providing two implicit benefits:

  • I don’t have to get all the WCF Ria Services code working before I can make configuration work and…
  • The design now allows me to substitute virtually any persistence mechanism (database, Xaml configuration files, etc.) to back these business objects.

Further, these objects are part of the ViewModel, and facilitate binding the View to the ViewModel (as discussed in my mini-tutorial on MVVM).

  

Implementation

We’re now (finally) ready to implement this, and as an experiment in open, honest and direct explanation I’m going to do this in real time, documenting my experience of creating the Unit Tests and the classes and their methods as I do it

One of the contributors to the slhvp project, Abby Fichtner (aka Hacker Chick) said to me just last night,

The great advantage of testing first is that it forces you to think about what the ideal API would be to each of your classes.

Exactically.  

The Configuration Objects

The first implementation issue is this:  I already have the following objects in the project:

It isn’t clear if the existing Item, Link and Topic (location) classes can be used for configuration, and I have a nagging feeling that I want something more. But here is where Agile development comes to the rescue: Design for what you need right now

Next up, A Real Time Walkthrough of Test-Driven Development….

MVVM – It’s Not Kool-Aid*

MiniTutorialLogo

 

 

 

 

SLHvpLogo

 

Okay, first, understand that I’m in the position of running through the streets yelling at folks “c’mere! ya’ gotta see this!” and what I’m pointing to is the incredible new invention of… a laptop computer. Something that is undeniably amazing and cool, but everyone else on my block has already got one.

Second, and much worse, I’m about to show you how I used a “pattern” that you either have already embraced, or that you’ve been avoiding like the plague because the folks who are running around shouting “MVVM! MVVM!” sound just like the folks who were running around shouting “MVC! MVC!” and “OOP! OOP!” and “COM! COM!”…  you get the idea.

Many of us are still recovering from the last five fads that caused us to go out and buy dozens of books and break our head on the latest/greatest trend, only to have it be “oh so last year” by the time we fully grokked it.

 

Drinking The Kool Aid*

Kool Aid Man

 

But this is different. Honest.

Here are three heretical assertions about MVVM:

  1. It is not all that different from what you are already doing
  2. It is not hard to understand or to do
  3. You will write better code, and you’ll write less code.

 

Typically, when a pattern or practice comes along, there is a steep learning curve, and the cognoscenti will tell you that it takes a very long time to truly master the approach. Feh. And not so, at least not this time. Let’s go over the assertions above, and I’ll explain, briefly, what you need to know to profit from MVVM.

Disclaimer: I’m not saying this is all you’ll ever need to know about MVVM, I’m saying if you know this, you can benefit from MVVM on any non-trivial application, while you’re learning more.

While I’m disclaiming, please note that I’m writing very specifically about a Silverlight 4 project and that I’ve been coding with MVVM for about a half hour.

 

It’s Not All That Different and It’s Not That Hard

We’ve been talking about n-tier development, decoupling, scoping, visibility and related topics since at least 1990. I’m pretty sure that when they were cracking the Enigma machine in World War II, they discussed decoupling the code-breaker module from the UI (did they have UI then?)

MVVM, at its heart has three core concepts, only the third of which is new, but that difference is all the difference in the world when you’re writing a Silverlight application that you want to be able to maintain and create unit tests for (Yes, I owe a blog post on Test-Driven design, but one glass of grape juice at a time).

MVVMSketch

 

 

Core Concept #1:  Separate your User Interface concerns (View) from your Business objects and behaviors (View Model) and from your data/persistence layer (Model).

Core Concept #2 Don’t Look Up

We tend to conceptualize the View (User Interface objects) at the top, the ViewModel (objects that provide the UI with its data and behaviors) in the middle and the model (often the persistence layer) at the bottom.  The View can know about the ViewModel, the ViewModel about the Model, and the Model, like the cheese, stands alone.

Core Concept #3 – And this is the killer: Binding.

In MVVM the mechanism for the ViewModel to provide data to the View, is for the View to set the ViewModel as its DataContext.  That is so cool; it takes a while to realize the implications.  Further, we don’t just bind data, as I’ll show below.

Why Would You Want To Do That, & What Does It Cost?

The huge advantages of using binding and making the VM the datacontext for the View is that you write less code and, equally important, your behaviors and state are all separated from the UI and thus you have enormously increased the testability of your application. (It is a bear to try to test a UI object because the pesky UI gets in the way. ViewModels have no UI, they have just the things you want to test: “does it behave as expected? and is the data correct at any given instant?”

So, the cost is negative; that is, by adopting MVVM you don’t work harder, you work less, and in exchange for doing less, your code is easier to write, to read, to maintain and to test. Not bad.

 

Names

Simplifying is one thing, over-simplifying another, and there is an elegance in the chosen names. 

The Model is that which the application is modeling. Calling this the database layer or the persistence layer loses site of the fact that the  model might be virtually any time of information in virtually any format.

Calling the top layer the View, rather than the User Interface is important both to emphasize that it is just one of many possible views of the model, and to keep clear that the User Interface comprises both the appearance and the behaviors and the View is concerned only with the appearance.

The ViewModel is the bridge between the Model and the View; and the ViewModel thus owns responsibility for binding the relevant data to the view and for handling user actions appropriately, whether the response is in the widget, elsewhere in the View or in other parts of the application.

A Practical Example

To see this at work, we’ll start by creating a new Silverlight Application. (Complete source code is available here)

Immediately add a new UserControl and name it PeopleView. Here is the Xaml for the UserControl:

<UserControl x:Class="MVVMWithBehaviors.PeopleView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">

<Grid x:Name="LayoutRoot" Background="White">
<ListBox Name="Names"
Background="Beige"
Width="200"
Height="250"
HorizontalAlignment="Center"
VerticalAlignment="Center"></ListBox>
</Grid>
</UserControl>
For completeness, here is the Xaml for MainPage.xaml
<UserControl x:Class="MVVMWithBehaviors.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:me="clr-namespace:MVVMWithBehaviors"
d:DesignHeight="300" d:DesignWidth="400">

<Grid x:Name="LayoutRoot" Background="White">
<me:PeopleView HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" />
</Grid>
</UserControl>

 

Note: If my solution were named HVP I’d have the following projects to support this model:

HVP
HVP.Web
HVP.Model
HVP.ViewModel
HVP.View
HVP.Tests

The advantage, for me, is that when I wish to touch a method or property in another class, the compiler will let me know if I’m crossing a project boundary (I’ll need a using statement) and that is a great time to double check that I have my visibility correct (e.g., a class in the View project can include ViewModel but not vice versa)
 
Next we’ll create PeopleViewModel, as a class.  The job of this class is to expose the properties (and as you’ll see, the methods) that we want the View to bind to.  Specifically, we want the ListBox within the view to bind its ItemsSource property to a collection of People, and we want the Person object to have a property which will display the name of that person. The complete source code is shown here:
 
   1: using System.Collections.ObjectModel;
   2: using System.ComponentModel;
   3:  
   4: namespace MVVMWithBehaviors
   5: {
   6:    public class PeopleViewModel : INotifyPropertyChanged
   7:    {
   8:       public class Person
   9:       {
  10:          public string Name { get; private set; }
  11:          public Person( string name )
  12:          {
  13:             this.Name = name;
  14:          }
  15:       }
  16:  
  17:       private ObservableCollection<Person> people;
  18:       public ObservableCollection<Person> People
  19:       {
  20:          get { return people; }
  21:          set {  people = value; }
  22:       }
  23:  
  24:       public PeopleViewModel()
  25:       {
  26:          MockGetDataFromTheModel();
  27:       }
  28:  
  29:  
  30:       private void MockGetDataFromTheModel()
  31:       {
  32:  
  33:          string[] firsts = new[] 
  34:             { "Tom", "Dick", "Harry", "Joe", "John", "Ringo" };
  35:          string[] lasts = new[] 
  36:             { "Liberty", "Papa", "Hanselman", "Heuer", "Brown", "Gu" };
  37:  
  38:          var r = new System.Random();
  39:          people = new ObservableCollection<Person>();
  40:          for ( int i = 0; i < 10; i++ )
  41:          {
  42:             people.Add(
  43:                new Person(
  44:                   firsts[ r.Next( firsts.Length ) ]
  45:                   + " "
  46:                   + lasts[ r.Next( lasts.Length ) ] ) );
  47:          }
  48:       }
  49:  
  50:       public event PropertyChangedEventHandler PropertyChanged;
  51:       private void OnPropertyChanged( string propertyName )
  52:       {
  53:          if ( PropertyChanged != null )
  54:          {
  55:             PropertyChanged( this, new PropertyChangedEventArgs( propertyName ) );
  56:          }
  57:       }
  58:    }
  59: }
 

We start by defining a Person (lines 6-15) and then we give the PeopleViewModel class a property People which is an ObservableCollection of Person objects.  The constructor (lines 24-27) calls a method that mocks up getting data from the Model; in this case I just generate ten names on lines 30-48   The final code implements INotifyPropertyChanged, which is not required yet, as the only property we have is an Observable collection.

 

Binding

We are now ready to bind the ListBox inside the View class to the ViewModel.  Add the following two lines to the ListBox declaration in PeopleView.xaml
 
ItemsSource="{Binding People}"
DisplayMemberPath="Name"
and then add this to the constructor in the code behind:
 

DataContext = new PeopleViewModel();

Running the application will now display the data from the ViewModel in the View
 

Behavior

The design of the Silverlight HVP says that when an object changes its state (e.g., the user changes the current item in a list box) the View object will notify the state object of the change. The State object then raises the StateChanged event to which all the View objects have subscribed, and each resets its state.
 
It would be nice to avoid having code in the View to manage the State Change notification; we’d like to bind this as well as the data, thus increasing the overall testability of the project.  Unfortunately, as of now, there is little support for this built into Silverlight (though there is some, using ICommand, with ButtonBase and HyperLink derived classes) 
 
The solution is to be friends with John Papa, who pointed me to the Expression Blend Samples project on CodePlex, which, when installed, provides a library that includes, among other things, the wondrous CallDataMethod, enabling you to trigger a method in your ViewModel based on an event in your view(!)
 
Since I had to spend quite a bit of time figuring out how to make this work, I thought I’d walk through it here. It is very easy, once you know how, but the project doesn’t yet provide the necessary instructions. Begin by going to the Expression Blend Samples page and downloading the latest release (which currently is from July 12, 2009 and marked Alpha.  This will put a .msi file on your disk, and running that will install the samples; unfortunately it will do so shockingly quietly, and you’ll have no idea what to do next.
 
Here’s what you do:  in your project you’ll need to add two references. The first is to System.Windows.Interactivity which on my machine is in:
 
c:\Program Files (x86)\Microsoft SDKs\Expression\Blend Preview for .NET 4\Interactivity\Libraries\Silverlight\System.Windows.Interactivity.dll
 
the second is Expression.Samples.Interactivey, which on my machine was in:
 
C:\Program Files (x86)\Microsoft Expression\Blend 3 Samples\Silverlight\Design\Expression.Samples.Interactivity.dll
 

You’ll now modify the view class to include the namespaces:
 
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:si="clr-namespace:Expression.Samples.Interactivity;assembly=Expression.Samples.Interactivity"

and finally, you modify the control (the listbox) to add the trigger and behavior

<ListBox Name="Names"
Background="Beige"
Width="200"
Height="250"
HorizontalAlignment="Center"
VerticalAlignment="Center"
ItemsSource="{Binding People}"
DisplayMemberPath="Name">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<si:CallDataMethod Method="HandleSelectionChanged" />
</i:EventTrigger>
</i:Interaction.Triggers>

</ListBox>


The EventTrigger has a property for the EventName; indicating that this trigger will fire when the event SelectionChanged is raised for the ListBox.  The CallDataMethod has a property Method for the name of the method to invoke. Since the ViewModel class is the data context, you don’t need to indicated which BindingToMethodsclass supplies the method, any more than you need to indicate which class has the property People to which the ListBox’s ItemsSource is binding.

Just add that method to the ViewModel class…

public void HandleSelectionChanged()
{
System.Windows.MessageBox.Show( "Update the state!" );
}

… and start your program. When you change the selection, the method you’ve bound to will be called.

In the Silverlight HVP this will allow us to bind the event notification to the SelectionChanged event, further decouplit’s the control from its data and logic. The technical term for this is “good.”

 

Overall Impact of Refactoring for MVVM

While this  is not an exhaustive understanding of MVVM by any means, with these fundamentals, it became obvious how to break up my code, and I found that there was less of it, and it was more intention-revealing.

In fact, the code-behind for my View classes have no code at all except setting the dataContext; and the ViewModel code is short and extremely readable.

 

All in all, I find MVVM well worth the small cognitive startup costs; yielding a very natural separation of concerns, and perhaps equally important, exposing far more of the program to unit tests, and thus driving down the overall time to release.

.

 

 

-----------------------------------

* In 1978 cult leader Jim Jones induced 900 followers to commit “revolutionary suicide” by knowingly drinking cyanide-laced grape Flavor Aid. To the chagrin of General Foods, the cultural memory of the event is that they drank Kool Aid and the expression. To drink the Kool Aid has evolved to mean “to embrace without reservations, the ideas of a strong leader”

Dynamic Blog Posts DynaPosts

Blog posts are by their nature static. It is not good form to go back to an existing blog post and update it, but often what I want is to keep everything on one page and have a quick way to notify that the page has been updated.

Starting today, I’ll do that on the right hand column. Look for a section titled DynaPosts which will list the dynamic posts, and the last time they were updated.  I’ll kick it off with a DynaPost on using VS 2010

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

Configuration & Decoupled Modules

MiniTutorialLogo

SLHvpLogoNoBorder

Two architectural demands for the Silverlight HVP, which are common to many larger applications, came together this week and crystallized into a design that looks to solve a couple other, unanticipated requirements.   Specifically, we knew that (1) we wanted to have configuration files and that (2) we wanted each module to be created independently of all the other modules. After some discussion, thrashing, input from some great folks at CodeMash, and further review, the design that has emerged allows us to implement two other less thought-through requirements: (3) the ability to restore the state of the application to an earlier condition and (4) the ability to save the state of the application when it is shut down.

The New Design For Configuration

All of this is much easier to understand by diving into the design that has emerged.  While the UI has not been determined, the core modules have been identified, and it is easier to conceptualize them with images; even if they don’t necessarily reflect how the modules will be presented to the user.

Function Vs. UI

Below are two sketches of potential User Interfaces for the same four objects; neither of these represents a considered UI design, but rather are here to make concrete the underlying structure that would support such disparate designs. (Click on images to enlarge)

Standard Mockup.bmml

In the standard mock-up (which may well represent the standard UI), the HVPItemsControl contains a list of all the items (videos, animations, etc.) that will be viewed in this HVPSet. 

The Current Item selected (or defaulted to)   determines the topics to be listed in the HVPLocationsControl and the hyperlinks listed in the HVPLinksControl.

Selecting a location causes the HVPPlayer Module to jump to the corresponding location. Selecting a new Item causes the HVPLocationsControl and the HVPLinks Module to fetch their new data

Selecting a link causes a new HVPSet to be created, potentially with its own Items, each of which has its own locations and links.

Distinguishing the Module from its UI

Alt Mockup

Before discussing configuration, event and state management, let’s look at a quick mock-up of another UI for these four primary modules (excluding the speculated Cloud Module)

The goal of creating this second mock-up, again, is to help wrap our heads around the difference between the functionality of the various modules, and their appearance (UI).

It should be quite easy to create a UI like this just with with templates, though no one is suggesting that this amalgam of different approaches is a serious design.

(Though, I must admit, I like the links appearing in bubbles, perhaps with a soft popping sound as they animate into existence from a point, expanding outwards).

Configuration

The requirement is that each module can be created in any order, and that no module is required, nor does any module know about any other. There are a number of ways to architect for this; though the problem is both constrained and (therefore?) simplified by the decision to create a composite application using MEF.

My strong inclination is to treat design of anything you are not about to code as a form of optimization: best left until you know what is needed. I’m a firm believer in Emerging Design, which, for me comes down to the recognition that you cannot know, in advance, what your architecture should be, because both the requirements and the design will evolve in response to the very act of building the application. 

You can, and should,  however, distinguish between a flexible architecture and a brittle one. One great way to do so is to throw ideas at the architecture and see if it has to change significantly every time you add a feature or a new way of approaching the problem. If the architecture nimbly adjusts and, better, expands on the requirement to reveal new possibilities, you are in great shape. (If it creaks and threatens to break with every new idea, then it is time to rethink!)

We have made the following decisions, to be implemented in the next three weeks:

  • MEF will be used to compose the application
  • An Event Manager (HVPEvents) will be created, and each module will register with HVPEvents when created by MEF
  • Events will signal a change in state of the current HVPSet   [footnote 1]
    • Modules will check the state object to determine what their current configuration should be
  • Configuration will be created first as objects, then persisted with Xaml   [footnote 2]
Markup Model Equals Object Model – Rob Relyea 

The rest of this posting will focus on two key ideas:

  1. Configuration and state persistence will be captured in objects and persisted with Xaml
  2. Modules announce only that their state has changed; interested modules then chek the current state.

Configuration, Objects, Xaml and Persistance

The state of a module is represented by a corresponding state object (e.g., HVPLocationState). The state of the application at any given moment is held by an ApplicationState object and represented as an HVPSet. The ApplicationState is, in turn, composed of the module state objects. Thus, the state of the application illustrated above would be represented by an HVPSet object that contains an HVPLocationState object, an HVPItemsState object and an HVPLinksState object. Note that there is no state object for the player as the player’s state is determined by the other objects (at least at this moment).

[Note, the state objects are not implemented in the current release, and are really mental placeholders for a final design. The goal, however, is to have objects that correspond to the information stored in the Xaml configuration file]

The ApplicationState object will initially only exist in memory. In time, it will be persisted either locally (local storage) or on a server, and accessed via a URL.

I’ll walk through this below, but note that this design will be implemented in stages, roughly:

  • First stage: we only know about configuration state, and that is hard-wired
  • Stage 2: we know about configuration state by reading a Xaml file and creating the objects
  • Stage 3: we know about configuration state by reading Xaml files (plural) identified by the Modules and assembling the configuration state
  • Stage 4: we can return to a previous state by storing a collection of HVPSet objects in memory, each of which consists of state objects for each module
  • Stage 5: we can persist state by writing the members of all the HVPSet objects to Xaml files.
  • Stage 6: The state of the application can be persisted by a service which returns a URL to that state. The user can then store that URL (to resume later) or send it to someone else (“Check out this very cool video and note the links to our site!”) that will allow another user to restore to the exact state that was saved, including the location in the video, the other items enqueued, the links displayed, etc.

 

Configuring Each Module

When a module is added to the application by MEF it will register itself with the HVPEvents class. [footnote 2]

Initial Configuration

The module will ask the HVPState for its own state object (e.g., the HVPLocation module will ask for the HVPLocationState object). If that object is not null, the module will use the state object to configure itself. 

When an object wishes to raise an event, it will send a message to HVPEvents which will, in turn, raise the appropriate event. The event will signal modules that subscribe to that event that they need to obtain their State object and their use of the state object will be identical to their actions in the initial configuration.

Let’s walk through a couple scenarios:

Bootstrapping when the user selects a video or set of videos

In this scenario the application has not started on the user’s machine, and the user makes a gesture (e.g., clicks on a link) to “watch” a video or an animation, or more likely an entire “experience.” In any case, the URL resolves to an HVPSet which is passed to the application on start up.

As the Application bootstraps it creates the  ApplicationState (a Singleton). The ApplicationState is given the Uri of the selected HVPSet, which returns a Xaml file. The ApplicationState asks the ConfigurationParser to convert the Xaml into an HVPSet.  In version 1, the HVPSet that is created has the Uri of the HVPItemsState.xaml file.

When MEF adds the HVPItemsModule, the HVPItemsModule requests the HVPItemsState object from ApplicationState. The AppliationState requests the HVPItemsState from the HVPState, which in turn asks the ConfigurationParser to read the HVPItemsState.xaml file and to return an HVPItemsState object which it then holds a reference to. The HVPState object also returns a copy of the HVPItemsState to the HVPItemsModule(by way of the ApplicationState object.) The HVPItemsModule then sends a message to HVPEvents which in turn raises the ApplicationStateChanged event.

The HVPLocationModule / HVPLocationState objects and the HVPLinksModule / HVPLinksState objects are created in much the same way.

When the HVPViewer is initialized, it obtains the current HVPItem from the ApplicationState which it uses to determine what type of HVPFrame to create. The HVPFrame  in turn creates the appropriate HVPPlayer which, in its turn, obtains the item using the same mechanisms.  The HVPViewer registers to obtain StateChange notifications so that if a different HVPItem is requested the correct Frame and Player can be created.

Handling User Generated Events

While an item is displaying the user can take any of the following actions:

  • Click on an item in the ItemModule
  • Click on a topic in the LocationModule
  • Click on a link in the LinksModule
  • Stop the application 
  • Request a snapshot of the current state of the application
  • Request a new set from the server (by whatever gesture the user began the application)

Clicking on an Item causes the HVPItemsModule to send a message to HVPEvents which raises the ApplicationStateChanged, which in turn causes the HVPLocation module and the HVPLinks module to re-set their state based on the current item.

Clicking on a topic causes the LocationsModule to send a message to HVPEvents which raises the ApplicationStateChanged, which in turn causes the the HVPLinks module to re-set its state and the HVPPlayer to seek to the requested location.

Clicking on a link causes the HVPLinksModule to send a message to HVPEvents which raises the ApplicationStateChanged, which in turn causes all the modules to set their state based on the new HVPSet. (Each link is tied to an HVPSet with its own set of Items).

In a version after V1, Stopping or closing the application or requesting a snapshot will (probably) cause a dialog box to open to ask the user if state should be saved, which is accomplished by having the ApplicationState save its current  HVPSet either locally or on a server, with a Uri returned which is then saved locally.

Design Simplification

In the current design the only event is the ApplicationStateChangedevent. For now, therefore, we will collapse HVPEvents into the ApplicationState object, and modules will not need to register, they will obtain the ApplicationState Instance and request that it fire the ApplicationStateChanged event.

Marker Reached, TimeObject Created, TimeReached

An earlier iteration of this design designated a number of other events that are now subsumed under the ApplicationStateChanged event, including the events needed to signal the HVPPlayer that the HVPLinks module has created a WatchedTime collection (for elapsed times at which it needs to be notified) and the ability for the HVPPlayer to notify any interested modules that a WatchedTime has arrived or that a Marker has been reached.

All of these are now handled as described above; that is, e.g., when the HVPPlayer reaches a Marker or a WatchedTime it updates the ApplicationState which in turn fires off an ApplicationStateChanged event, and the interested modules reset their own state accordingly (e.g., the HVPLinks module might add a link to its list).

----------

[1] Particular thanks to Jeremy D. Miller for helping me think this through at an Open Spaces at CodeMash.
[2] Special thanks to Rob Relyea and to Glenn Block

Severely Decoupled Configuration

MiniTutorialLogo

SLHvpLogo

[ Jan 23 - Note that the design specified here has been significantly updated

In the spirit of a glass-house (you get to see everything as it happens), open source project, here is a draft of how I see handling configuration for the Silverlight HyperVideo Platform  -- this will be modified in the next iteration to take more advantage of the services provided by MEF.

Design Goals

  • It doesn’t matter what order the modules are loaded by MEF.

  • Maximum encapsulation, minimal coupling

EventManager

Rather than having objects publish and subscribe directly, this will be mediated by what for now I’m calling an EventManager. This object may be build on Prism’s event aggregator, and may take more advantage of MEF’s ability to provide services.

When, below, I talk about a module firing an event, what I actually envision is that the object firing the event calls a method on the EventManager, which in turn first the event (objects subscribe with the EventManager)

Known Events
In a subsequent version, the EventManager won’t necessarily know in advance all the events it must manage but right now I assume it does. The known events are:

  • ICareAboutItemLists
  • ICareAboutItems
  • HereIsAnItemList
  • HereIsAnItem
  • HereIsANewLink
  • LocationReached

Modules & Core Abstract Clases

While any number of modules may be loaded into the SLHVP, we initially anticipate that there will be modules deriving from the following abstract classes

  • Viewer
  • Frame
  • ItemsList (Items)
  • LocationsList (Locations)
  • LinksList (Links)

Application startup

On startup, the Viewer is instantiated and is given the initial configuration file’s url. It subscribes to  ICareAboutItemLists and HereIsANewLink. It then uses the configuration file to determine which Frame to instantiate.

When a Frames instantiated it subscribes to HereAreTimeObjects, HereIsAnItem, SeekTo, and fires off ICareAboutTimeObjects

When the ItemsList module is instantiated it subscribes to HereIsAnItemsList and fires of ICareAboutItemLists

When the LocationList module is instantiated it subscribes to HereIsAnItem, and fires off ICareAboutItems

When the LinksList module is instantiated it subscribes HereIsAnItem and LocationReached and fires off ICareAboutItems

ICareAboutItemLists

When ICareAboutItemLists is raised, the Viewer responds by raising HereIsAnItemsList and passing the config file url in the event args. That file has the list of items to display and the url of the config file for each item

HereIsAnItemsList
The ItemsList module responds to HereIsAnItemsList by reading the config file, creating its list of items, and storing the url of the config file for each item. It then raises HereIsAnItem

HereIsAnItem
HereIsAnItem is responded to by LocationList, which read the config file. LocationList creates all its links as an internal object, and displays them

This event is also responded to by LinksList, which examines the configuration and may find markers or time elements. If it finds neither, it has nothing to do. If it finds markers, it makes a collection of the markers so that it can respond to LocationReached. If it finds Time elements it creates a collection of TimeObjects and fires off HereAreTimeObjects.

The frame also responds to HereIsAnItem by loading the item in the URL in the EventArgs and displaying that item

HereAreTimeObjects

The Frame responds to HereAreTimeObjects by getting the TimeObjects out of the EventArgs and adding them to its own TimeObjects collection.

MarkerEvents

When the Frame hits a marker, it fires the LocationReached event, providing a Location object which has the time elapsed
When the frame reaches a time that corresponds to one of its TimeObjects it:

  • Stops the timer
  • Fires off a LocationReached event
  • Destroys the corresponding TimeObject (so it won’t fire again)
  • Starts the timer

LocationReached

LinksItem  responds to LocationReached by putting up its appropriate link

User Clicks On A Link (SeekTo, and Links)
When the user clicks on a link in LocationsItem, the module raises the SeekTo event. The Frame responds to SeekTo as you would expect.

When the user clicks on a Links module link, it fires the HereIsANewLink, with the url of the config file for that link

HereIsANewLink
When the HereIsANewLink event is fired, the Viewer responds, chases the URL and fires off HereIsAnItemsList (see above for the Items response)

Video of the SLHVP First Release

SLHvpLogo

Brief Video Illustration

I’ve created a very quick video that shows the proof of concept version of the Silverlight HyperVideo Platform and describes a bit about the project. screencast

We are working on creating a page where the latest version will always be available for you to try out. Stay tuned, and thanks for your patience.

< br / >




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

Silverlight HVP Proof Of Concept Released!

SLHvpLogo

I’m incredibly proud to say that we were able to release the Silverlight HVP proof of concept alpha release on time, at 12:05 am Wednesday January 6, 2010 (GMT-5).  As noted in our release schedule this is the first of a series of releases scheduled for every second Wednesday.the dancer

While this first release exceeds what we promised for the Proof of Concept, it is still very much a hard-coded representation of what we plan to release in the  coming weeks. Our first major release will be in two weeks, on January 20, when we swap out the hard-coded modules and swap in the mef-based dynamic modules that show the true colors of our emerging design.

Key Features in the Proof Of Concept

  • Silverlight Media Framework player subclassed and placed in a view
  • Table of contents with hard-coded but live links that seek to the appropriate spot in the streaming video
  • Table of links with hard-coded but clickable links that appear at designated times as the movie progresses

Thanks to all for your continuing support.

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

Worth A Thousand Words

SLHvpLogo

 

 

In responding to a discussion on the HVP, I generated this image, which I think goes some way towards clarifying the recent posts.

ModuleNames
(Click on image for full size)

 

The discussion is here

As an aside, the best Greeking engine I’ve found is here; and, wonderfully, it also generates techno-babble.

Rapidly Evolving Design

SLHvpLogo

The problem with using a blog to track a rapidly evolving design, is that blogs don’t make for very fluid documents; the unwritten rule is that once posted, you ought not go back and substantially alter a post.

Matching Blog Posts to Discussions

I do want to use these postings to keep everyone up to date on the evolution and lessons being learned in the SLHVP project, but we also need a way to consolidate the discussion and the evolving understanding, and so each blog post will refer to a specific discussion on CodePlex where the ideas will be discussed and will evolve. I’ll then post a roll up of changes periodically, but not in response to each posting. The most recent post is being discussed here, where I have recognized that I violated my own design principles and backed away from two lines in the previous blog post. Here is what I wrote:

 

Your questions reveal that I have violated my own design principles: "Do not let the design get ahead of what you know" -- The right answer is, of course, to design only for what we know we need, and keep the design open enough to extend as new needs emerge. To answer your qeustions specifically:

…What I meant was that we know that videos will want to signal a marker has been encountered, and I can imagine that other frame components might want to signal that something has happened that is equivalent (you've reached the 4th level of play in this game)... then I went off the track and speculated that this should be handled by the Frame. But that is absurd.  The Frame might be the place to handle this, but I can easily imagine that there is a base class or interface that the video and game support or that there is a separate class they both associate with, etc. etc.  So let's just strike that statement (which I will do by editing my message and referring to this discussion.

2. [Each module will have its own xml config file] Here is where I really went over the edge. I totally retract this statement. Maybe it makes sense for each module to have its own configuration file, but we'll only know that once we have modules and we've worked with a single integrated configuration file (the manifest you have working). So let's please stay with the manifest until it is manifestly not working :-)

Please do join us in the ongoing discussion. Feel free to leave comments here about the form of the post, but substantive comments about the project will be seen by the most people, and those most involved, in the ongoing Discussions.

Thanks

 

jessesig

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

Extending the SLHVP Player to be a Platform

SLHvpLogo
This post is part of the Silverlight HyperVideo Platform  documentation

[Updated 1/5 10:50 GMT-5]

Everything Flows, Nothing Stands Still – Plato
Nothing Endures, But Change - Diogenes

The past few days have seen quite a flurry of design activity, and I’m quite sure some folks who have been following closely have been confused. This note will clarify, and also discuss design decisions made to move the project forward, and why these decisions were made. I have created a new discussion on the CodePlex site and I would invite your comments and feedback there, if that is convenient for  you.

Original Goals:

  • Build a HyperVideo player which would provide a better way to play our instructional (How Do I) videos and
  • Annotate the process from design to completion in a series of blog posts, as a way to discuss virtually every aspect of Silverlight

OpenSource and CodePlex

We decided to move the project to CodePlex (which took a few  months to get licensed) and open the project up to community involvement.  This is a wonderful thing, and has created unanticipated opportunities. 

My perspective on this project, buttressed by management expectations, is to foster as much community contribution as possible, but to take personal responsibility for every line of code in the project, to set coding standards, and so forth.

The project is being built with MEF which makes it composible and extensible. I envision 6 classifications for code created by the community

  1. Code accepted into the core project (process has been detailed on the Developer Page
  2. Code accepted into the plug-in extensions within the project
  3. Code that needs further work to meet coding standards but we anticipate accepting
  4. Modules that have been rejected as inconsistent with the project, but which can be housed outside of the project (even on another CodePlex project)
  5. Modules that a person or company develops intending to make them proprietary but to work with the project.

Key to this is that the first two represent code that will be in a release from the project, and the fifth option is open to any organization, commercial or otherwise, so long as they follow the Ms-PL license.

The Contributions and Influence of WL

As you may know, we have a commitment from WL (an e-learning startup) for 100 hours/week of developer time. They already have some code working that they are interested in adapting to this project and contributing to the core. Their stated intention is to contribute all this work into Ms-PL licensed code housed on CodePlex and also to try to build a product or products using the SLHVP as the engine.  That, as I read the Ms-PL is more than appropriate.

Two concerns comes to mind, and this was surfaced by WL itself from day 1:

  1. Will they distort the project to meet their own needs in a way that either precludes a more general use or freights the code with only tangentially relevant parts and/or
  2. Will they add complexity that we otherwise would not have

After working carefully with them and examining what they need and want, and what will be best for the project, I can unequivocally answer no to #1 and I can give a more nuanced answer to #2.

The short version is that they bring a more complex design, and with it they bring far greater flexibility and mission-appropriate features. Thus, yes, the project will end up more complex with their involvement, but it will not end up with unneeded or irrelevant complexity.  To be specific, all the additional complexity will be in service to features that are appropriate for the project.

Expanding the Scope

This would not work if I were to cling to an initial limited vision of the product, but it works great if we lift our vision a little higher.

I had a boss who said (paraphrasing):  “If the railroad companies had realized they were not in the rail business but the transportation business, we’d all be flying Union Pacific Airways.”

One very important aspect of my role in Microsoft is to provide “educational material” such as videos and mini-tutorials, but an arguably more important job is to explore new ways of conveying this information that greatly enhance customer satisfaction and involvement. That can be done by responding to user-suggestions and concerns (which we try hard to do) and also by exploring relatively radical new ways of conveying this information.

The Silverlight HyperVideo Platform

Over the past couple weeks the project has been re-conceptualized in somewhat broader terms, as evidenced by the new summary statement:

The SLHVP is an extensible HyperVideo platform to orchestrate media, data, user-experiences, and social-interaction into compelling applications.

What this means is that the SLHVP now anticipates providing more than just video and web links, but also, over time, animation and possibly interactive elements. To accomplish this, we are working towards the following key aspects of the design; most of which should be in place by the January 20 release

  • The application is a shell that loads its components via MEF
  • Each component stands alone, is configured from its own xml file
  • All configuration information is provided from one or more databases using WCF RIA Services
  • Each component publishes its events, and each event provides information for consuming modules in a class derived from EventArgs
  • Event management will be mediated by a class associated with the application; we are exploring Prism’s EventAggregator
  • Each component consumes those events that are of interest to it

We have identified the following modules for the first release

  • The Viewer – responsible for instantiating Frames
    • Frames are a way to display one or more control within the viewer – full design to come soon
  • The Derived SMF video player – essentially the SMF player adapted to work within our architecture
    • This will be the primary way to display videos
  • Frame will support a “Location Reached” event that can be triggered by (among other things)  We will need to handle the following occurrences and others much like them  [updated 1/5 – please see this discussion]
    • An injected marker being reached
    • A marker being reached
    • A position (elapsed time) in the video being reached
    • A location event from within a frame being fired
  • The ItemsListView that displays all the items that will be displayed in this session (this could be a single video, a series of videos, etc.)  The ItemListView will be subclassed to allow for various types of lists, including ordered lists and maps.  For V1 we will most likely have just an ordered list (display video a, b, c in that order)
  • The PostiionListView – either a stand alone module/viewer or one combined with the ItemsListView that allows seeking to specific locations within an item – this would be used, for example to seek to a specific topic within a video
  • The LinksView – some items (notably videos) will have a set of links that will either appear all at once or, more likely, as the topic they relate to is mentioned in the Frame.  These links will, typically, pause the current frame and cause a new frame to be created – e.g., will open a new video or a web page, or animation, etc.

The current (not yet released) code has a single xml file for creating all of these modules, but even if that is what we release on Jan 20, by early February each module will have its own configuration file. The format for these files will be well-established, and we’ve nearly finalized that already.    [updated 1/5 – please see this discussion]

As the first set of code comes from WL and our other contributors I will expand upon these descriptions and update our feature and task list accordingly.

Thank you all for your ongoing support and patience as we sort this out. I anticipate a great burst of productivity over the next six weeks or so.  Please be sure to see the newly updated schedule.

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

Configuration Files for Silverlight HVP

MiniTutorialLogo

SLHvpLogo
This mini-tutorial is part of the Silverlight HyperVideo Project documentation.

Taking Risks

One of the great pleasures, and total terrors of documenting this open-source application is that occasionally I have to offer up some half-baked ideas that risk displaying how little I know about a particular topic, but which are necessary to generate discussion. Caveat: this is such an entry.  I could have put this into the project documentation but I saw an opportunity to widen the audience on a topic that is important to Silverlight Programmers, even if not part of Silverlight itself.

Goal

 

We want the modules in the Silverlight HVP to be as flexibile as possible. Towards that end we’ve adopted two strategies:

  • Using the Managed Extensibility Framework (MEF) to make every module composable and extensible.
  • Using XML files to provide Just In Time configuration for each module.

XML Schemas

It will greatly simplify everyone’s work if we have agreed upon schemas, at least for the configuration files we know about:

  • slhvpInit.xml – initialize the application
  • slhvpTOC.xml – create a table of contents for a video
  • slhvpLinks.xml – establish which links will appear while a video runs and what to do when the user clicks on each

As a necessary first step, I’ve sketched out examples of slhvpTOC.xml and slhvpLinks.xml – these are not intended to be complete, but to generate discussion. They are posted here as a way to invite more folks into that discussion.

slhvpTOC.xml (draft example)

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <ConfigFile Name="TOC Configuration File" 
   3:             Guid="687DA074-8F94-43a9-AC23-46DF823F8A65"  
   4:             xmlns=http://slhvp.com/TOC>
   5:   <ConfigurationMetaData>
   6:     <Version>0.0.1</Version>
   7:     <Purpose Summary="Create a Table of Contents for a video" />
   8:     <![CDATA[
   9:     This configuration file is used to create the table of contents. The topics are listed as links, which cause
  10:   the video to seek forward or backward to the designated topic.
  11:     ]]>
  12:     <Module Name="slHVP Standard TOC Module version 0.1" 
  13:             Guid="D3E2AC2B-FD34-40b4-BC42-308F7956C7D9" />
  14:     <CreatedDate Format="AmericanShort" Date="01/01/2001" />
  15:     <Conditions>
  16:       <Condition Name="Advanced"
  17:                  Value="True" />
  18:     </Conditions>
  19:   </ConfigurationMetaData>
  20:  
  21:   <ConfigurationData>
  22:   <TOCEntries>
  23:     <TOC>
  24:       <Type> TOC </Type>
  25:       <SeekTo>
  26:         <SeekToTime>00:00:10:000</SeekToTime>
  27:       </SeekTo>
  28:       <Text> Introduction </Text>
  29:     </TOC>
  30:     <TOC>
  31:       <Type> TOC </Type>
  32:       <SeekTo>
  33:         <!-- Seek directly to an injected or existing marker -->
  34:         <SeekToMarker ID="LINQ" />
  35:       </SeekTo>
  36:       <Text> Introduction to LinQ </Text>
  37:     </TOC>
  38:     <TOC>
  39:       <Type> TOC </Type>
  40:       <SeekTo>
  41:         <SeekToTime>00:20:10:010</SeekToTime>
  42:       </SeekTo>
  43:       <Text> MVVM </Text>
  44:       <!-- Designate that this entry in toc is only idsplayed if 
  45:       the Advanced condition has been set to true -->
  46:       <Visibility Condition="Advanced" RequiredValue="True" />
  47:     </TOC>
  48:   </TOCEntries>
  49:   </ConfigurationData>
  50: </ConfigFile>
  51:  

The file consists of a header (lines 2-4) and two major sections – the meta-data (lines 5-19) and the listing of the (abridged) Table of Contents entries (lines 22 – 48). Notice that the final TOC entry (lines 38-47) is visible only if the condition “Advanced” is set to true, which it is in the Conditions section int eh meta-data (lines 15-18.

slhvpLinks.xml (draft)

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <ConfigFile Name="Links Configuration File" 
   3:             Guid="83ca650e-25ff-414d-adef-7aa790f9d858"  
   4:             xmlns="http://slhvp.com/Links">
   5:   <ConfigurationMetaData>
   6:     <Version>0.0.1</Version>
   7:     <Purpose Summary="Link time to hyperlink to action" />
   8:     <![CDATA[
   9:     This configuration file is used to create linkage among an elapsed time in a How Do I video with
  10:     the text of a new link to display at that time and then with the action to take based on the new link being clicked.
  11:     ]]>
  12:     <Module Name="slHVP Standard Link Module version 0.1" 
  13:             Guid="FB252D52-A603-4bf4-89C8-AA64E52D0343" />
  14:     <CreatedDate Format="AmericanShort" Date="01/01/2001" />
  15:     <Conditions />
  16:   </ConfigurationMetaData>
  17:  
  18:   <ConfigurationData>
  19:   <Links>
  20:     <Link>
  21:       <Type> Hyperlink </Type>
  22:       <Time>
  23:         <!--Time format is hh:mm:ss:msmsms-->
  24:         <StartTime>00:00:00:000</StartTime>
  25:         <!--Undefined end time - visible to end of video-->
  26:         <EndTime>0</EndTime> 
  27:       </Time>
  28:       <Text> About this video </Text>
  29:       <Action> WebPage </Action>
  30:       <URL> http://jliberty.com/aboutHyperlink.htm </URL>
  31:     </Link>
  32:     <Link>
  33:       <Type> Hyperlink </Type>
  34:       <Time>
  35:         <StartTime>00:05:11:010</StartTime>
  36:         <!--End time of 0 or missing end time both mean no end time, run to end-->
  37:       </Time>
  38:       <Text> What is Linq </Text>
  39:       <Action> Video </Action>
  40:       <URL> http://silverlight.net/learn/video#103 </URL>
  41:     </Link>
  42:     <Link>
  43:       <Type> Hyperlink </Type>
  44:       <Time>
  45:         <StartTime>00:12:00:110</StartTime>
  46:       </Time>
  47:       <Text> Linq Programming Animation </Text>
  48:       <!-- video pauses and is replaced by animation frame -->
  49:       <Action> Animation </Action>
  50:       <!--Required either a URL or a guid to a frame-->
  51:       <GUID>
  52:         E40D045A-4AC4-4ea9-8501-58F0E0407F61
  53:       </GUID>
  54:     </Link>
  55:   </Links>
  56:   </ConfigurationData>
  57: </ConfigFile>
  58:  

You can see that this format is quite similar to the TOC format, and one open question is whether we need an inclusive schema.

In this file, each Link has a type, where some of the possible values are

  • HyperLink (link to a URL)
  • Animation (link to a frame that supports animation
  • Text (link to a frame that displays non-html text)

 

Purpose of this posting

To reiterate, briefly, I have two goals with this posting:

  1. Generate discussion about what needs to be in the configuration files and whether this is a reasonable starting point and
  2. Follow through on the implications of my thinking about markers, links, etc.

Note that this topic is also under discussion here which is a great place to continue the discussion.

Polling Video – A Viable sub-second alternative?

SLHvpLogo

An interesting suggestion was made with regard to my intended use of embedded “heartbeat” markers.  Mike Loynd (WL) referred me to this fascinating article by John Deutscher (PM for IIS Media).  That caused me to experiment with the following code in the HVP Silverlight Video Player,

public partial class Player : Page
{
  private readonly DispatcherTimer timer;
 
  public Player()
  {
    InitializeComponent();
    timer = new DispatcherTimer { Interval = new TimeSpan( 500 ) };
    timer.Tick += new EventHandler( timer_Tick );
    timer.Start();
  }
 
  void timer_Tick(object sender, EventArgs e)
  {
    var position = CoreMedia.Position;
    var minutes = position.Minutes;
    var seconds = position.Seconds;
    var milliseconds = position.Milliseconds;
    TopPlaceHolder.Content = 
       string.Format("{0:d2}:{1:d2}:{2:d4}", 
       minutes, seconds, milliseconds);  
  }
 

 

Essentially, every 1/2 second I’m asking the streaming video for its position, which is returned as a timespan. Here’s a (cropped) snapshot of the player in action:

Timer

The advantages of this approach are:

  • No markers need be embedded, all the information about the TOC, links, etc, can be encapsulated in an xml file or database, and be applied to any video
  • Granularity (do care about 1/2 second intervals or 5 second intervals?) can be adjusted based on the media, the bandwidth, etc.
  • Adding links and other HyperVideo information can be applied to any video without having to modify the video in any way.

The key question is how often one can poll without noticeably affecting performance, but this does show a great deal of promise. More on this very soon.

The code for this is now checked into the Silverlight HyperVideo Project  as build 53344

Silverlight HVP Design, Refinements

MiniTutorialLogo

SLHvpLogo

Design Update 

This was posted on Dec. 29 and updated on Dec. 30. The significant changes are to the Configuration and Marker Events sections

This blog post extends the  previous post in which I discussed the IMarkerEventHandler interface and how it might be implemented.

Readers and Frames

The design calls for one or more Pages each of which may have any number of UI modules. The default case is to have a TableOfContents module, a LinksDisplay module and a Reader module.

A Reader houses Frames where a Frame is a set of controls.  The Reader knows which frame to create and manages the lifetime of Frames.

A given frame has a known set of controls. For example, Frame-Type-1 might house the  HVP-extended version of the Silverlight Media Framework player (as described in this blog post) and Frame-Type-2 might display an html page and have a set of navigation controls.   (More on readers and Frames early in January)

Configuration

We anticipate using XML configuration files (delivered via WCF RIA Services and instantiated by MEF into a collection of business objects that for now I’ll call  HVPLayout. 

Marker Events

The meaning and actions to be taken by a Frame in response to hitting a marker in the video will be managed by the IMarkerEventHandler (MEH) implementing class. as described in the previous post mentioned earlier. 

One approach is to have the Marker Event Handler class  own a collection of HVPMarkerEvent business objects, each representing one association between a marker, its time, its type (link, etc.) and whatever other information the MEH class will need to raise the appropriate event.  A second approach, and one that is gaining a lot of traction, is to bring in the EventAggregator from Prism.

Supporting Legacy Videos

The Silverlight HyperVideo Player will continue to support existing videos that do not have markers nor our config files by having a default layout in which there is a reader that takes up the entire page, and that reader contains a Frame that itself contains nothing but our extension to the SMF player.

Other Technologies

We are actively looking at when using an IoC (Inversion of Control) container such as Ninject would provide services that are not otherwise available. For now, we believe MEF will provide the Container services, configuration and interaction with Unit Test that we need.

Silverlight HVP Design Update

 

SLHvpLogo
This blog post is part of the documentation for the Silverlight HyperVideo Player Open Source Project

Design Change:

  1. Create an Interface: IMarkerEventHandler
  2. Optionally derive a base class MarkerEventHandler that implements the interface
  3. Instantiate MarkerEventHandler classes that are decoupled from the HyperVideo player

This change is designed to decouple the response to markers in a video from the other responsibilities of the Silverlight HyperVideo player.

IMEH 
[Click on image for full size]

Each MEH encapsulates a strategy for responding to markers.

Here are four examples of how a MEH might interact with markers.

  • Heartbeat markers – every n seconds, used as lookups into a data source to see if there is an action at that time
  • Synchronization markers – at known times, used to resynchronize, but the logic for what happens at a given time is independent of any marker event
  • Meaningful Markers  – traditional use of a marker that tells you what time it was raised and identifies what the marker indicates (tied to an event in the video)
  • Null marker – the MEH is responsible for whatever we choose but does not depend on markers in the video

There is, potentially, more than one way to have an MEH associated with a HyperVideo player:

Option 1: The HVP will have-a MarkerHandler. As the video is played, if a marker is encountered the HVP will invoke a method on the contained MarkerHandler.

Option 2: (Looser coupled). The application will instantiate a player and a MEH object and when the player encounters a marker it will raise an event to which the MEH will subscribe. If the MEH needs to have the player take an action (e.g., pause or resume) the MEH will fire an event to which the player will subscribe.

These ideas are not fully developed but are thought through enough to move forward and with luck, sufficiently flexible to be easily modified as design emerges.

 

Details about the Silverlight HyperVideo Player Project can be found at our CodePlex Site and information on joining the Development effort can be found on the Developer Page within the project documentation.

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