Jesse Liberty - Silverlight Geek Page view counter

Persisting the Configuration (Updated)

MiniTutorialLogo

[Updated and expanded on March 5] 

HVP-Config-DB For this week’s release of the Silverlight HyperVideo Platform we are committed to having configuration information retrieved from a database. To accomplish this we need (want?)

Smooth-streaming videos that we can use to illustrate the relationship among Items, Topics and Links and

A Database in which to store the configuration information

Step 1 was accomplished by

  • Creating the videos
  • Creating image files
  • Uploading the videos and images to MSN where the videos were encoded for smooth streaming and URLs were returned for the image and for the video
  • Watching the videos and noting where we want to mark topics and links
  • Adding that information to the database

Step 2 was accomplished by creating a Database with four tables

  • Listables
  • Items
  • Topics
  • Links
The Listables table’s relationship with the other three is isomorphic to the relationship between the Listable base class and the derived classes Item, Topic and Link.  All of this is captured in the database diagram shown above.

 

 

Foreign Keys

SELECT      dbo.Items.ID AS ItemsID, 
            dbo.Items.ItemUri, 
            dbo.Listables.ID AS ListablesID, 
            dbo.Listables.TextToDisplay, 
            dbo.Listables.ImageSource, 
            dbo.Items.MyListableID
FROM        dbo.Items INNER JOIN
            dbo.Listables ON 
               dbo.Items.MyListableID = dbo.Listables.ID

The Sets, Items, Topics and Links tables each represent part of an object, with the remaining part held in Listables.  This “normalization” of the database reduces the duplication of data, and thus reduces the likelihood of database corruption. 

The Sets, Items, Links and Topics tables each have a column titled MyLinkableId which is a foreign key linked to the key ID field in the Linkables table. This lets us create views such as this definition of the ItemsView

As shown in the image, the column MyListableID in Items and the column ID in Listables are used to join the two tables together into a complete Item.

An Item’s Links and Topics

The second set of connections from each of Links and Topics to the Listables (colored blue) represent the has a ItemsViewrelationship from Items to Topics and from Items to Links.

Thus, the database has captured all the object relationships, but has translated it into relational terms.

The next step is to use the Entity Frameworks to translate back to objects, and WCF RIA Services to create those objects both on the database server and on the Silverlight client.

Adding Data to the Tables

For what follows, assume I have the following videos, topics and links:

Assume I have a set of videos in this relationship

Set – 0 Items:

  • Item – Hypervideo Overview (video)
  • Item- Items and Links (video)

Topics for HyperVideo Overview:

  • Topics and Links
  • Multiple Items
  • Clicking a Link

Links for HyperVideo Overview:

  • Silverlight: Get started
  • Sets
  • MVVM

We will have course have authoring tools for adding this information to the database, but for now let’s add it by hand.

Step 1 – Make an entry for the Set

-- set
insert into Listables (TextToDisplay, ImageSource) values ( ' ', ' ')

Step 2 – Man entries for the two items

Each entry is in two parts: the “base class” table, Listables, and then the “derived class” Items:

insert into Listables (TextToDisplay, ImageSource) values ( 
'HyperVideo Overview', 
'http://content1.catalog.video.msn.com/…7928.JPG')
insert into Items (MyListableID, ItemUri) values
(2,
'http://msnvidweb….b73822cd9f88.ism')

Step 3 – Enter the Topics for the first item

insert into Listables (TextToDisplay,ImageSource) 
   values ( 'Topics and Links', ' ')
insert into Topics(MyListableID,MyItem,Offset) 
   values (14,13,25)

insert into Listables ( TextToDisplay, ImageSource) 
    values ( 'MultipleItems', ' ')
insert into Topics(MyListableID,MyItem,Offset) 
    values (15,13,52)

insert into Listables ( TextToDisplay, ImageSource) 
    values ( 'Clicking A Link', ' ')
insert into Topics(MyListableID,MyItem,Offset) 
    values (16,13,85)

Note that each of the three topics is entered in two parts, the Listable and the Topic.

Step 4 – Enter the Links for the first item

insert into Listables ( TextToDisplay, ImageSource) 
   values (  'Silverlight: Get Started', ' ')
insert into Links(MyListableID, MyItem, Offset) 
   values (17,13,37)

insert into Listables ( TextToDisplay, ImageSource) 
   values (  'Sets', ' ')
insert into Links(MyListableID, MyItem, Offset) 
   values (18,13,49)

insert into Listables ( TextToDisplay, ImageSource) 
    values ( 'MVVM ', ' ')
insert into Links(MyListableID, MyItem, Offset) 
   values (19,13,90)

We would then enter the topics and links for the first item as well. 

Examining the raw data and the relationshiops

When we’re done, we can do some queries to make sure that the data makes sense. First, we’ll examine the Listables table; ListablesResultswe should see the “base” data for the set, for each item and for all the topics and links:

That is, in fact, exactly what we see. Each entry has a unique ID (in this case an integer, in a future release a GUID). Entry 1 is the Set (which has no text or image). Entry 2 is the first Item we entered.

Entries 3-7 are the Listable parts of the Topics for the first item and entries 8-13 are the Listable parts of the Links for the first item.

Note that Listable ID 13 represeents the second item, and that is followed by the Listable parts for the topics and links of the second item.

 

To see these relationships, we can query the TopicsView to see that the database has captured the Text to display, the offset (in seconds) of where to jump to if a topic is chosen, and the relationship between the Topic entry, its own Listable entry, and the Listable entry for the Item that the topic relates to.

select TopicsID, MyListableID, TextToDisplay, MyItem, Offset 
from TopicsView

The result of this query displays 5 columns, 

TopicsViewTopicsID is the unique ID for each Topic entry

MyListableID is the ID of the entry in Listable that completes this topic (i.e., the base part of this Topic)

TextToDisplay is the text that will be displayed in the Topics window

MyItem is the ListableID of the item that these topics are for (e.e., Listables 2 and 13 shown above)

Finally, Offset is the number of seconds into the video that clicking on the topic will scrub to.

This work is licensed under a Creative Commons license.

When Is It OK To Hack?

MiniTutorialLogo

This mini-tutorial is part of the SLHVP documentation

 

One of the goals of the Silverlight HyperVideo Project is to demonstrate best practices.  So when is it okay to throw in a quick hack to get things working?

CutDownPlayerCase in point: as I approached the release this week for the latest alpha,  I noted that the player was not updating when the user clicked on a topic, though the links were appearing as if  the player had been advanced.

To make the issue clear, in this image you see a cut down version of the player. Each item (video) has its own set of topics and links. The topics are shown as soon as the video starts, the links appear as the video plays.

If the user clicks on a topic (lower left) what should happen is that the video (middle) jumps to that topic and the scrubber  (below the video) should advance to indicate where in the video the topic begins, relative to the start of the video.

(Click on image to see it full size)

After a bit of debugging (and some frantic calls to the Vertigo folks who wrote the Silverlight Media Framework, we were able to see that the problem was in the binding:

<SmoothPlayer:Player Style="{StaticResource SLHVPTemplate}"  x:Name="smoothPlayer">
    <hvp:HVPCoreMediaElement x:Name="corePlayer"  
    SmoothStreamingSource="{Binding URI, Mode=TwoWay}" 
    AutoPlay="True"
    Position="{Binding Offset, Mode=TwoWay}" />
</SmoothPlayer:Player>

Checking the source code for the SMF (available here) we found that Position is a dependency property and was not responding to the Binding as we expected.

Since the folks at Vertigo owned that code and were convinced they could fix this in the next release, I opted to take their change an copy it into my project. To encapsulate the hack, however, I created the HVPCoreMediaElement, derived from the CoreSmoothStreamingMediaElement. 

 

using System;
using System.Windows;
using Microsoft.SilverlightMediaFramework.Player;

namespace SilverlightHVP.View
{
   public class HVPCoreMediaElement : 
           CoreSmoothStreamingMediaElement
   {
      public TimeSpan PositionOverride
      {
         get { return ( TimeSpan ) GetValue( PositionOverrideProperty ); }
         set { SetValue( PositionOverrideProperty, value ); }
      }

      public static readonly DependencyProperty PositionOverrideProperty =
             DependencyProperty.Register( 
                "PositionOverride", 
                typeof( TimeSpan ), 
                typeof( CoreSmoothStreamingMediaElement ),
             new PropertyMetadata( HVPCoreMediaElement.OnPositionOverridePropertyChanged ) );

      private static void OnPositionOverridePropertyChanged( 
            DependencyObject d, DependencyPropertyChangedEventArgs e )
      {
         HVPCoreMediaElement source = d as HVPCoreMediaElement;
         source.OnPositionOverrideChanged();
      }

      private void OnPositionOverrideChanged()
      {
         // Hack!!, to databind to Position
         Position = PositionOverride;
      }
   }
}

I could then modify the binding

<SmoothPlayer:Player Style="{StaticResource SLHVPTemplate}"  x:Name="smoothPlayer"     >
    <hvp:HVPCoreMediaElement x:Name="corePlayer"  
    SmoothStreamingSource="{Binding URI, Mode=TwoWay}" AutoPlay="True"
    PositionOverride="{Binding Offset, Mode=TwoWay}"  
</SmoothPlayer:Player>

And all was right with the world.   This was minimally intrusive, and I was very pleased with it.  I should have known.

In For A Penny…

The problem, of course, is that now that I’m binding the new PositionOverride I’m reading wonderfully, but writing, not so.  There are a lot of ways to fix this, but the easiest, fastest and perhaps ugliest is to add a second binding. After all, binding to Position was working great for setting, and PositionOverride is now working great for reading. 

<SmoothPlayer:Player Style="{StaticResource SLHVPTemplate}"  x:Name="smoothPlayer"     >
    <hvp:HVPCoreMediaElement x:Name="corePlayer"  
    SmoothStreamingSource="{Binding URI, Mode=TwoWay}" AutoPlay="True"
    PositionOverride="{Binding Offset}"  
    Position="{Binding PlayerPosition, Mode=TwoWay}" />
</SmoothPlayer:Player>

If this were the only change, maybe okay, but unfortunately we have to hack the VM as well,

public TimeSpan Offset {  get { return state.Position; } }

public TimeSpan PlayerPosition
{
   get { return state.Position; }

   set
   {
      if ( value > previousPosition + Interval )
      {
         previousPosition = value;
         state.Position = value;
      }
   }
}

Oh What A Tangled Web We Weave…

This is so ugly, and so likely to end up being a headache when we are ready to undo it, that I’m very tempted to find a cleaner solution. On the other hand, I know that we’re actively working on SMF version 2, and that even before that I may have an interim release that makes the whole problem go away, so my Faustian bargain is to comment the hack

/*   HACK!! We are binding the getter of Offset to the Position of the CoreSmoothStreamingMediaElement
     but we are binding the setter to the PositionOverride property of the (temporary) class HVPCoreMediaElement that
     derives from CoreSmoothStreamingMediaElement.  Also note that this is two way binding and we need both the getter
     and the setter. 
     To Fix: 
        1. Combine move get and set from PlayerPosition to Offset and remove PlayerPosition
        2. Change Binding in SmoothStreamingPlayer to bind to Offset, two way
        3. Remove file (and class) HVPCoreMediaElement.cs
*/

 public TimeSpan Offset {  get { return state.Position; } }

 public TimeSpan PlayerPosition
 {
    get { return state.Position; }

    set
    {
       if ( value > previousPosition + Interval )
       {
          previousPosition = value;
          state.Position = value;
       }
    }
 }

Let the Flame Wars Begin

“Well?,” as Howie Mandel’s tiny alter-ego Bobby asks, “what would you say?”

This work is licensed under a Creative Commons license.

The United Kingdom & The Republic of Ireland

I am extremely pleased to say that thanks to the very hard work of Guy Smith-Ferrier, and the generosity of Microsoft UK, Microsoft Ireland, Microsoft User Group Support Services and Microsoft US,  and the work and welcome of numerous user groups in the UK and Ireland, I am able to announce that I’ll be talking at the following events in mid-April.

  UK  Monday, April 12: The .NET Developer Network in Bristol.
Presentation: Silverlight 4 MVVM and Test Driven Development

April 13 and 14:  Microsoft Tech Days, London. [ Twitter tweme: #TechDays ]
sluguk_thumb_5FBB67DF Tuesday April 13: Silverlight User Group / London .NET User Group.

Wednesday April 14: The Next Generation User Group, Cambridge.

Thursday April 15: Black Marble User Group, Leeds

Friday April 16: NEBytes, Newcastle Upon Tyne

Monday April 19* Scottish Developer’s User Group, Edinburgh

Tuesday April 20 Scottish Developer’s User Group, Glasgow


Thursday April 21 Belfast

 

   Ireland


Friday April 22 Dublin

Minute_Man_Statue_Lexington_Massachusetts
* April 19 is celebrated as Patriot's Day in Massachusetts and Maine. What could be better than to celebrate the Battle of Lexington, fought in Concord by the men of Acton, while in Scotland?

Presentations

Introduction to Application Development With Silverlight 4 

This presentation is targeted at .NET programmers new to Silverlight or who wish a review of the fundamentals of building an application in Silverlight 4. Topics will include

  • Drag and Drop development
  • Xaml and Code
  • Layout and Controls
  • Data, Data-binding, Validation and Async-validation
  • Templates and The Visual State Manager (Time allowing)

Building A Highly Extensible, Decoupled Silverlight Open Source Application with MEF and RIA Services using Lean, Test Driven Development, An International Team of Volunteer Programmers,  and lots of Advil.

This talk will use the Silverlight HyperVideo Platform open-source project on CodePlex as a case study in building highly extensible Silverlight applications. Among the topics we will focus on are:

  • New features in Silverlight 4 and how they made life easier
  • The Managed Extensibility Framework (MEF) added to Silverlight 4
  • WCF RIA Services for connection to a back-end db
  • Handling inter-module communication when the requirements are that modules cannot assume which other modules will be created, there can be no dependencies on order-of creation and unanticipated modules must be able to communicate with existing modules.
  • Using Markers, Injected Markers and polling to trigger events while viewing a video.
  • A Quick introduction to Lean, TDD and Kanban

Silverlight 4,  MVVM and Test-Driven Development

  • MVVM and Silverlight to build test-driven programs
  • Understanding Refactoring and Dependency Injection
  • A Walk through of a non-trivial application
This work is licensed under a Creative Commons license.
Posted by jesseliberty | 6 comment(s)
Filed under:

Silverlight Test Driven Development – Part II

MiniTutorialLogo

 

 

 

 

At the end of Test Driven Body Snatchers I promised to follow up with a walkthrough of real-world Test Driven Development. What gets into me? 

Well, a promise is a promise. 

Walking Through Test Driven Development

Waybackmachine3[1] The set up is this: We’ve designed the  Silverlight HyperVideo Platform using the MVVM pattern

We’re going to take a trip in the way-back machine, and design  the ItemsViewModel class (the VM in MVVM)  using Test-Driven Development. 

 

Begin At The Beginning…

We start out by examining the existing ItemsView class (the V in MVVM ) which is implemented in ItemsView.xaml (and its code-behind):

<UserControl x:Class="SilverlightHVP.View.ItemsView"
    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="ItemsList"
               Background="Beige"
               Width="200"
               Height="250"
               HorizontalAlignment="Center"
               VerticalAlignment="Top"
               ItemsSource="{Binding Items}"
               SelectedItem="{Binding CurrentItem, Mode=TwoWay}"
               DisplayMemberPath="TextToDisplay">
      </ListBox>

   </Grid>
</UserControl>

Designing the View Model

We are now ready to create the ItemsViewModel, which will serve as the data-context for the binding shown in the ListBox.

iStock_BoyWithBrainXSmall And here the world turns upside down. 

In the absence of test-driven development, I’d think about this a lot and make all sorts of decisions before writing a line of code. I’d decide, no doubt that the ItemsViewModel needs to provide a collection of Item objects to serve as the ItemsSource, and thus the Items property of the class would be a collection of Item objects. 

Since CurrentItem is bound to the SelectedItem, I’d try to figure out if that is a property with its backing value held in the ItemsViewModel or in, for example, the state object that is shared by all the ViewModel classes.

You can do all that, and you can make unit tests for it, but test-driven development works differently.  In TDD you make much smaller design decisions, write much smaller bits of code, and create a rapid cycle of three steps:

  1. Determine one key thing  you believe the ItemsViewModel class must provide and write a test asserting that it does provide that. Run that test. It will fail.
  2. Write just enough code in ItemsViewModel to make the test pass. No stop, just enough, no more. Good. Run the test again, it should pass.
  3. Repeat*
* Old joke: a programmer  was stuck in the shower because the shampoo bottle said “apply, lather, rinse, repeat.”

 

The Discipline of TDD

Yes, it is infuriating to write the simplest thing when you believe you already know more. But a funny thing happens… you find that you are never lost, confused, befuddled or even in need of a debugger. You only did a little bit and the test either passes or it fails. If it fails, it is trivial to figure out what is wrong; after all you probably only wrote a couple lines of code.

Creating The Test in Visual Studio

HVPTests To get started, I’ll add a project to the SilverlightHVP solution of type Test Project and I’ll name it SilverlightHVP.Tests.

Visual Studio will add the project, add a file UnitTest1.cs and add two new files to the solution: Local.testsettings and TraceAndTestImpact.testsettings. It also adds a reference to Microsoft.VisualStudio.Quality.

Tools.UnitTestFramework. Once the project is added to the solution, I can right click on the new project and choose Add->NewTest, bringing up the Add New Test dialog box.  I recommend experimenting with each of the tests offered, but for now, I’ll just  AddNewTest choose Basic Unit Test and name it ItemsViewModelUnitTests. 

Visual Studio will create the class and a first test method, and adorn each with the appropriate attributes.  Delete TestMethod1 and it is time to write (and name!) our first test method.

The First Test

So; what is the very least we think the ItemsViewModel must do? Let's return to the ViewModel and note that the ListBox.ItemsSource property is binding to a ItemsViewModel property named Items. 

A quick look at the Silverlight documentation reveals that the ListBox.ItemsSource property is of type IEnumerable. That is, a collection. We don’t yet know what is in the collection, but we do know that the ItemsViewModel must have a property Items that returns an IEnumerable of something. Let’s create a test for that.

So what is the test actually testing for? The minimum is that the Items property, an IEnumerable<object> (that is, an enumerable list of something) is not null.

Our naming convention is to identify the thing we are testing and what should be true. The name, therefore, is ItemsProperty_ShouldNotBeNull.

 [TestMethod]
 public void ItemsProperty_ShouldNotBeNull()
 {
 }

Creating the body of the test requires testing the property of an ItemsViewModel instance; so the first line of the test will create the beast. 

CreateInstanceOfIVM

When we attempt to make an instance, we immediately get the feedback that something is amiss; no surprise; the class doesn’t exist yet. Visual Studio is ever-helpful, however, and it offers to generate the classs for you. Let’s have it do  that.  Hey! Presto! a new file ItemsViewModel.cs is generated in the test project. That’s not where we’ll want it, but for now it is just fine.

Our first test line no longer shows an error, and oh, by the way, creating this line was a forcing function on the design: we needed a class of type ItemsViewModel.   ItemsProperty Similarly, we now will attempt to retrieve the Items property as an enumerable, which of courses will generate both an error (no such property) and an offer to create the property for you.  Once again we’ll let Visual Studio generate the needed stub.  With that, we can test that Items is not null:

TestFailed

Place your cursor on the name of the test method and press Control-R, T; this will run this one test and display the results in a window, as shown.

Our dreams and ambitions are fulfilled; the test failed as we expected it to!  Great.

(click on images for full size)

Making The Code Pass The Test

Now we write just enough code for the test to pass. Watch it! Just enough and no more.

 class ItemsViewModel
 {
    public IEnumerable<object> Items 
    {
       get { return new List<Object>(); }
       set { }
    }
 }

Since I can’t instantiate an interface, I chose a very simple class that implements IEnumerable. Notice that I’ve not populated the list; all I’ve done is write enough code to satisfy the test. This is pedantic, rigid, annoying and incredibly useful. The design emerges based on the needs, the needs are expressed by the tests, and the code never goes beyond the (thought through and tested) requirements. 

A real though not driving benefit is that the tests become both insurance and documentation; and unlike other documentation, as long as you “rigidly” make sure you run all the tests every time you make any change, the documentation never goes out of date.

The Second Test

At this point we know that we want more than for the property to be non-null; we want it to have items. Let’s test for that:

 

      [TestMethod]
      public void ItemsProperty_ShouldNotBeNull()
      {
         var itemsViewModel = new ItemsViewModel();
         IEnumerable<object> items = itemsViewModel.Items;
         Assert.IsNotNull( items );
      }

      [TestMethod]
      public void ItemsProperty_ShouldReturnListOfObjects()
      {
         var itemsViewModel = new ItemsViewModel();
         IEnumerable<object> items = itemsViewModel.Items;
         Assert.AreNotEqual<int>( 0, items.Count<object>() );
      }

Running Two Tests

You can run the second test just as you ran the first, but we really want to make sure that it is wicked easy to run all the tests every time. Click in the class, but not on either test, and press Ctrl-R, T.  This causes both tests to be run, and sure enough the first test (ShouldNotBeNull) passes, but the new test fails.

Once again, we write just enough code to make this pass.

 class ItemsViewModel
 {
    public IEnumerable<object> Items 
    {
       get { return new List<Object>() { new Object() }; }
       set { }
    }
 }

And running the tests again, both pass. And so it goes. Step by tiny step. 

Factor Out Common Code In Tests?

Most of you are probably starting to itch terribly, as you look at the two tests and note that the first two (of three!) lines are identical.  Yikes! Somebody factor that out, quick!

And we will, but before we do, let me note that this is not a given; in fact doing so is somewhat controversial.  First, how to do it, then the controversy.

[TestClass]
public class ItemsViewModelTests
{
   private IEnumerable<object> items;
   [TestInitialize]
   public void ItemsProperty_SetUp()
   {
      var itemsViewModel = new ItemsViewModel();
      items = itemsViewModel.Items;
   }

   [TestMethod]
   public void ItemsProperty_ShouldNotBeNull()
   {
      Assert.IsNotNull( items );
   }

   [TestMethod]
   public void ItemsProperty_ShouldReturnListOfObjects()
   {
      Assert.AreNotEqual<int>( 0, items.Count<object>() );
   }

   [TestCleanup]
   public void ItemsProperty_CleanUp()
   {
      items = null;
   }
}

The trick here is that the testing framework will run each test in the following sequence:

  • If there is a method marked [TestInitialize] run that first
  • Run the test method
  • If there is a method marked [TestCleanup] run that last

The controversy is this: you do not want any dependencies between tests. It can never be allowed that running one test affects another. That is, for example, ShouldReturnListOfObjects should return the same results if it is run before or after ShouldNotBeNull or even if ShouldNotBeNull is not run at all.

One way to protect yourself is to have each test be fully self-contained. A second way is to ensure that CleanUp eliminates any side-effects. 

Or Not…

James Newkirk, one of the brighter lights in the field, author of nUnit and xUnit, explains in some detail why he opposes using Setup and Cleanup (TearDown) methods.

I’ve taken the liberty® of quoting one of the key paragraphs:

The problem that I have with SetUp in this case is twofold. The first and primary complaint is that when I am reading each test I have to glance up to BeforeTest() to see the values that are being used in the test. Worse yet if there was a TearDown method I would need to look in 3 methods. The second issue is that BeforeTest() initializes member variables for all 3 tests which complicates BeforeTest() and makes it violate the single responsibility pattern. 

Brad Wilson, Newkirk’s partner in crime, elucidates four objections to the use of setup and teardown, which I summarize here,

  • You can’t tell what the test is doing without looking at the setup, which can be far away in the file when you have a number of tests
  • If the setup or teardown throws an exception it can be very confusing as to what is wrong
  • There is only one setup and teardown per set of tests, and that presumes every test needs the same setup; a dangerous and misleading assumption that makes the test harder to understand.
  • It is too easy to have the setup code change the environment for tests run later in the series; breaking the rule that tests are independent.

==========

I am incredibly grateful to Abby Fichtner for helping me past the initial hurdles in Test Driven Development (though she may argue I’m not yet past them!). 

She recommended to me, and I recommend to you this excellent tutorial by Jason Olson from Channel 9 (where you can now watch Silverlight TV)

 

jessesig

This work is licensed under a Creative Commons license.

Answering A C# Question

I often receive questions about topics covered in one or another of my books, and I respond, most often, privately. Every once in a while, however, a question comes along that may be of more general interest. This question, though about C#, has a profound effect on Silverlight programming as well…

Question:

… I still can't figure out when I would need to create an interface when designing my application….

 

Short Answer

When you want to abstract out what is required from how that requirement is met.  

Full Answer

The short answer is correct as far as it goes, but it doesn’t help at all [footnote 1]

The somewhat longer answer is to start with some of the premises of writing Clean Code:

  • Each method should be very short and do just one thing
  • Each class should have one easily articulated area of responsibility
  • Classes should know what other classes do but not how. 

Let’s look at how that might play out…

You might start off by refactoring into a Note class and a FileManager class like this:

 

using System.IO;
using System;

namespace Interfaces
{
   class Program
   {
      static void Main( string[] args )
      {
         var np = new NotePad();
         np.NotePadMainMethod();
      }
   }

   class NotePad
   {
      private string text = "Hello world";

      public void NotePadMainMethod()
      {
         Console.WriteLine( "Here I would interact with you and offer you a writing surface" );
         Console.WriteLine( "Then when you push the right button, I ask FileManager to " );
         Console.WriteLine("print the file..." );

         var fm = new FileManager();
         fm.Print(text);
      }
   }


   class FileManager
   {
      public void Print(string text)
      {
         Console.WriteLine( "I'm pretending to backup the old version of the file and then " );
         Console.WriteLine( " print the text you sent me " );
         Console.WriteLine( " printing {0}" , text );
         var writer = new StreamWriter( @"c:\temp\HelloWorld.txt", true );
         writer.WriteLine( text );
         writer.Close();
      }
   }
}
   
   
   

This console program is stripped of all error checking and all three classes are in one file to keep things simple. The idea is that the NotePad class interacts with the user, obtains a string to print, and then sends it to the FileManager whose job is to see if the file exists, if so make a backup, and then write the user’s text to the file (presumably we’d open a file save dialog rather than just assuming the user wants to write to c:\temp\HelloWorld.txt).

Adding A Second Writer

After creating the above, you realize that there will be times that you will want to write to, e.g., Twitter.  You could put in a branching statement:

using System.IO;
using System;

namespace Interfaces
{
   class Program
   {
      static void Main( string[] args )
      {
         new NotePad().NotePadMainMethod();
      }
   }

   class NotePad
   {
      private string text = "Hello world";
         
      public void NotePadMainMethod()
      {
         var dest = "Twitter";
         switch ( dest )
         {
            case "File":
               var fm = new FileManager();
               fm.Print( text );
               break;
            case "Twitter":
               var tm = new TwitterManager();
               tm.Tweet( text );
               break;
         }
      }
   }


   class FileManager
   {
      public void Print(string text)
      {
         // write to file
      }
   }

   class TwitterManager
   {
      public void Tweet( string text )
      {
         // write to twitter
      }
   }
}
   
   
   

Adding An Interface

This begins to get ugly, and more important, the NotePad class is now entirely iStock_connectTwoWiresXSmalldependent on both the FileManager class and the TwitterManager class.  It is cleaner, easier to maintain, and far easier to test, if we remove those dependencies.

The first step in doing so is to have the NotePad not know which class will take care of writing the message; all it needs to know is that some class that knows how to “Write” will do the work.  We accomplish this by creating an interface, Writer[footnote b] that has a Write method.

 

 

   interface Writer
   {
      void Write(string whatToWrite);
   }

We then have the FileManager and TwitterManager classes implement this interface:

   class FileManager : Writer
   {
      public void Write( string text )
      {
         // write to a file
      }
   }

   class TwitterManager : Writer
   {
      public void Write( string text )
      {
         // write to Twitter stream
      }
   }

At this point, we return to the NotePad and it can instantiate the class it wants as a Writer:

      public void NotePadMainMethod()
      {
         var w = new TwitterManager();
         w.Write( text );
      }

That is step 1 in decoupling the NotePad from the other classes; now all it knows is that it has a Writer, which can be one or the other of the streams (or any other class that implements that method) but we’re hard coding which implementing class to use (in this case TwitterManager) in the NotePad class… not great.

Dependency Injection

iStock_InjectionRedXSmall Dependency Injection is one of those terms you really want to work into your conversation at every conference you attend. It marks you as a cutting edge, in the know kind of geek. 

Here’s how it works.  You don’t want to hard-code the dependency into NotePad because that makes for code that is hard to maintain and hard to test (the technical term is “bad.”)

What you can do, instead, is “inject” the dependency at run time. You can inject in a number of ways, the most common of which are:

  • Constructor injection
  • Property injection
  • Parameter injection
  • Using a Factory
  • Using an Inversion of Control (IoC) container

(Yes, IoC container may be even cooler than dependency injection. More on IoC below, but not much more)

Constructor injection just says that we’ll let the Notepad know which type of writer it is going to use when we create the class:

   class NotePad
   {
      private string text = "Hello world";
      private Writer w;
      public NotePad( Writer w )
      {
         this.w = w;
      }
         
      public void NotePadMainMethod()
      {
         w.Write( text );
      }
   }

Notice that we pass in an instance of Writer, stash it away in a member variable and then NotePadMainMethod just uses it.  The actual instance is not created in NotePad, it is created in whomever instantiates the NotePad and “injected” into NotePad through the constructor.

Property Injection works the same way, but instead of passing in the writer through the constructor, you set a property,

      public Writer MyWriter { get; set; }
         
      public void NotePadMainMethod()
      {
         MyWriter.Write( text );
      }

Now whoever instantiates MyWriter just sets the property and NotePad can take it from there. 

Parameter Injection, as you can, by now imagine, eschews having a member variable, and just passes the type of writer into the method as a parameter

      public void NotePadMainMethod(Writer w)
      {
         w.Write( text );
      }

Factory Pattern and IoC Containers

Each of these three approaches has its advantages, but none of them scale very well. To solve this problem, developers often turn to the Factory Pattern which allows for another level of indirection: an object that creates other objects (the factory).  We won’t go into that as it isn’t essential to understanding interfaces, but I will also mention that beyond the Factory, when you want the ability to “compose” your application at run time, with totally decoupled objects (that is, at run time you’ll decide what writer the NotePad will use, and neither the writer nor the NotePad need depend on the other) you can then turn to Inversion Of Control (IoC) containers; a big topic covered in some detail here, and here.

The Curve, and Being Behind It

Reading Scott’s great review of Alt.NET and Open Spaces and many topics related to the above; I am reminded of a cartoon in which you see a man and woman in a tree, while others are running by holding torches, and the woman says to the man, “How come it seems like everyone else is evolving but us?

More from me on Open Spaces, Dependency Injection, Alt.Net and much else coming soon. You can join me in working through all this while creating a truly amazingly fun open source project here, the documentation for which is here.

jessesig

 

 

 

 

----

footnote 1: Old joke: two guys are in a helicopter over Washington state, and the fog comes in too fast; they are totally lost and running low on fuel.  The chopper pilot pulls up next to an office building, knocks on the window and when a man comes to the window, hollers “Where am I?”

The guy looks at him and says “You’re in a helicopter” and shuts the window.

The pilot flies directly to the airport and lands safely. His passenger, stunned, asks him, “how did that help?”  “Oh,” says the pilot, “I was in a life and death situation, and asked a perfectly reasonable question. He gave me an answer that was both true and totally unhelpful; so I knew right where I was: Microsoft Tech Support.”

(With apologies to the terrific and truly helpful people at tech support, who will please have a sense of kajf;320 <abend>)

 

footnote b: Notice that my interface is named Writer, not IWriter.  I’d like to say that I had the courage of my convictions to stop putting the Silly I in front of every interface (IWrite, IClaudius, IThinkThereforeIAm…) but it took reading Bob Martin’s wonderful book Clean Code to get me to step up.

This work is licensed under a Creative Commons license.

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: ,
Next