Archive for October, 2008

Just wanted to take a moment and talk about a recent project I did that went live earlier this week in conjunction with the PDC conference.

Modelsremixed.com is a Silverlight-based site that supports Microsoft's "Oslo". You can learn more about "Oslo" on the site. All of the animations were done by hand in Blend. There's a couple of things I love about the site. The design is simple - super clean, but looks cool and doesn't get in the way. The other aspect of the site I love is the video section. This is the most complete video player I've authored to date. It combines 4 streaming sources and one progressive download. Corey Schuman's video slider saved me a ton of time (I still remember the first one I wrote in Silverlight 1 - no comparison). All of the controls have tooltips, and the video player includes an embeddable version and integrated sharing options (Digg, Del.icio.us, etc.).

Check it out and let me know what you think.

Amazon has finally updated the listing for my forthcoming Silverlight 2 book. The total page count landed at 448, and the release date has been moved up to November 3rd - Amazon was reporting 300 pages and November 8th for a looong time.

So with that in mind, as we enter the final week before the book releases, here's a peek at the table of contents.

In keeping with some of my prior posts, here's some low-quality sneak peaks at a few more of the projects too:

Some collisions with multiple angled surfaces can be seen here.

Last time, I posted a horizontal carousel. Here is a vertical version.

Here is an example of a chain pull.

And finally, two particle system examples. A particle fountain, and a node garden.

As always, apologies for the low res, low frame rate videos, but I need to minimize the file size as much as possible.

Wow, what a crazy week. I had two Silverlight projects due at work. One was developed in beta 2, and had to be compiled in RC0, and both versions are wrapped on the page. Then on Wednesday, I converted my development environment to the RTM version. Took longer than I anticipated, but managed to knock out the next project fully in the RTM.

I have also converted some of the projects I posted here.

The Bird Hunt game is here.

Tank Combat is here.

Etch-A-Sketch is here.

The Filmstrip gallery is here.

The modified Filmstrip (auto running) is here.

For the code/explanation of the filmstrip effects, you can check out the blog post here.

I have some ideas for some additional projects to put up to demonstrate some different techniques, and I will have more information about my book and some additional project movies soon. Only a couple of weeks until it's out!

Here's a peek at the cover of my forthcoming Silverlight 2 Animation book.

Foundation Silverlight 2 Cover Image

Foundation Silverlight 2 Cover Image

Here's a look at a couple more projects from the book.

The first one is a particle comet.

I've seen a lot of talk over the past year about carousel navigation and how to implement it. There's a couple of good examples out there, but I also included two in my book - a horizontal one as well as a vertical, Rolodex-style one. I've explained how to create them in detail - from layout to control. Here's an example of the kind of control you can build in.

At work, we recently had this concept for a filmstrip gallery/navigation system, but decided to go in a different direction. I thought the idea was pretty cool, so I'm going to share the Silverlight project with you in this post. The project creates a filmstrip gallery like the one shown here:

Filmstrip Gallery

Filmstrip Gallery

You can download the source code for this project here.

Upon opening the project, you'll want to right-click the HTML file and select "Set as start page" from the pop up menu. The project contains the usual App.xaml and Page.xaml files, and I added another object called FilmFrame.xaml. This object is a single frame from a film strip, as shown in the following image.

FilmFrame User Control

FilmFrame User Control

The control contains a PNG image for the black frame of the film, and several yellow text fields. I wanted the completed strip to look like real film, so I went with the live text, and I update it programmatically as each image is loaded. The frame also contains an image which is loaded out of an XML file parsed at run time (we'll talk more about that in a moment).  The reflection of the frame is just a copy of the frame XAML that is in its own canvas with an opacity mask, and is scaled to -1 Y.

Inside the Page.xaml.cs file, the app parses an XML file to get the images, builds two copies of the filmstrip, and then starts them moving. Here's a breakdown of the code.

The code starts out by declaring a list to hold the parsed image paths, an integer to track the number of elements parsed, and a double for the filmstrip's X velocity. 

private List Images;
private int NumItems;
private double FilmVelX = 1;

Inside the Page() constructor, several events are set up. The navigation is a bit of a shortcut since this was a proof of concept piece - three buttons (left, stop, right). Each one has a Click event added to it - the handler functions are relatively simple - I'll let you take a look at those on your own.

public Page()
{
    InitializeComponent();
    Images = new List();
    this.Loaded += new RoutedEventHandler(Page_Loaded);
    NavLeft.Click += new RoutedEventHandler(NavLeft_Click);
    NavStop.Click += new RoutedEventHandler(NavStop_Click);
    NavRight.Click += new RoutedEventHandler(NavRight_Click);
    MoveFilm.Completed += new EventHandler(MoveFilm_Completed);
    MoveFilm.Begin();
}

The Loaded event is where the app goes and grabs the config file. The file lives in a "config" folder inside the ClientBin folder, and is a very simple XML file with a list of image elements.

private void Page_Loaded(object sender, RoutedEventArgs e)
{
    Uri configFile = new Uri(Application.Current.Host.Source, "config/config.xml");
    WebClient rest = new WebClient();
    rest.DownloadStringCompleted += new
        DownloadStringCompletedEventHandler(rest_DownloadStringCompleted);
    rest.DownloadStringAsync(configFile);
}

The parsing code that's called when the DownloadStringCompleted event fires is the same method I described in my post on reading the Twitter RSS feeds.

OK, with the basic stuff out of the way, let's talk about how the app works. The Page.xaml file contains a background image and three canvases. The FilmCanvas canvas holds the frames, the FilmCanvas2 canvas holds a copy of the frames to provide a seamless wrap, and the Controls canvas holds the nav buttons described earlier.

Once the XML file is parsed, the BuildFilm() function is called. This function creates the filmstrip frames, placing a copy of each frame in each of the filmstrip canvases. The code to create the filmstrip frames looks like the following listing. This code updates the text on the frame based on the for loop index, and adds the parsed image to the DisplayImage and DisplayImageReflection containers.

FilmFrame nextFrame = new FilmFrame();
nextFrame.MouseEnter += new MouseEventHandler(Frame_MouseEnter);
nextFrame.MouseLeave += new MouseEventHandler(Frame_MouseLeave);
nextFrame.MsgTopFrameNum.Text = nextFrame.MsgBotFrameNum.Text = i + "";
nextFrame.MsgBotFilmAdvIn.Text = "→ " + i + "A";
nextFrame.MsgBotFilmAdvOut.Text = "→ " + (i + 1) + "A";
Uri thumbnail = new Uri(Application.Current.Host.Source, Images[i]);
nextFrame.DisplayImage.Source = new System.Windows.Media.Imaging.BitmapImage(thumbnail);
nextFrame.DisplayImageReflection.Source = new System.Windows.Media.Imaging.BitmapImage(thumbnail);

The copy of the frame is done with similar code. Since it's a copy, it uses the same thumbnail image. Once the loop has completed, the FilmCanvas2 canvas is positioned on the main page to the right of the FilmCanvas canvas.

Canvas.SetLeft(FilmCanvas2, Canvas.GetLeft(FilmCanvas) + FilmCanvas.Width);
Canvas.SetTop(FilmCanvas2, Canvas.GetTop(FilmCanvas));

The Completed event for the MoveFilm storyboard handles the motion of the filmstrips. The first thing the event handler function does is to move FilmCanvas and FilmCanvas2.

Canvas.SetLeft(FilmCanvas, Canvas.GetLeft(FilmCanvas) + FilmVelX);
Canvas.SetLeft(FilmCanvas2, Canvas.GetLeft(FilmCanvas2) + FilmVelX);

Next, it goes through a series of checks to see if the canvases need to be wrapped. This code ensures that no matter which way the strips are moving, they are positioned appropriately to wrap.

// first strip has moved off-canvas to the left,
// so adjust it to the end location of the second strip
if (Canvas.GetLeft(FilmCanvas) < -FilmCanvas.Width)
{
    Canvas.SetLeft(FilmCanvas, Canvas.GetLeft(FilmCanvas2) + FilmCanvas2.Width);
}
 
// second strip has moved off-canvas to the left,
// adjust it to the end location of the first strip.
else if (Canvas.GetLeft(FilmCanvas2) < -FilmCanvas2.Width)
{
    Canvas.SetLeft(FilmCanvas2, Canvas.GetLeft(FilmCanvas) + FilmCanvas.Width);
}
 
// first strip is moving to the right,
// position the second strip to the left of the first
if (Canvas.GetLeft(FilmCanvas) > 0)
{
    Canvas.SetLeft(FilmCanvas2, Canvas.GetLeft(FilmCanvas) - FilmCanvas2.Width);
}
 
// second strip is moving to the right,
// position the first strip to the left of the first.
if (Canvas.GetLeft(FilmCanvas2) > 0)
{
    Canvas.SetLeft(FilmCanvas, Canvas.GetLeft(FilmCanvas2) - FilmCanvas.Width);
}

When you run the app, you'll see the filmstrip build - one of the things I like is that the strip will build out and add the images as they download. You can use the nav buttons to speed up the strip or change its direction, and when you mouse over an item, a red border highlight becomes active and the strip stops moving. When you mouse out, the border hides and the strips moves again. The app could easily be augmented to display a full size image when a filmstrip element is clicked, or any other number of cool applications. If you do anything with it, shoot me an email and let me know, I'd like to see it.

Just to get the creative juices flowing, here's the source code for a variation of the program. This one uses a second timer to gradually spin up the speed of the strip until full motion video is achieved (about 10-15 seconds). You can see the example running here. Anyone want to tackle a drawing program that loads the frames into the strip as they're drawn? =)