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? =)

7 Responses to “Filmstrip Gallery”

  1. 2008 October 03 - Links for today « My (almost) Daily Links says:

    [...] Errors Jesse Liberty with more on his Dependency Properties – Precedence series Jeff Paries’ film strip gallery - really, check this one out. Mike Snow on How to Apply Styles in Silverlight – Part I Bill [...]

  2. David Roh says:

    Hi Jeff,

    Awesome!

    Just what I needed - thank you for sharing.

  3. John McFetridge says:

    Love this example in fact I have combined it with an example of jeff prosise to produce the following:
    http://www.sandkeysoftware.com/SL2/Filmstripnew/Filmstrip.Web/FilmstripTestPage.html

  4. jeff says:

    Hi John -

    Cool! I like the way you used the filmstrip! Thanks for sharing…

    Jeff

  5. Andrew says:

    That filmstrip annimation with the running horse is awsome.

  6. Reno says:

    Hi Jeff…thanks for share this great example….Im just a beginner and I have combined it with a ScottGu’s example [http://weblogs.asp.net/scottgu/]….
    it has more info in the .xml file (you called it config.xml)….and the idea is hmm….display that info when you select a pic (or frame)….

    if you want the sourcecode…please write to cobain.r@gmail.com…..

    thank you Jeff…gracias!!

    Reno.

    PS: Im sorry for my bad english lol…;P….

  7. Sandeep says:

    I’m using your filmstrip for developing a website for my college, But it is using too much cpu, Please help.. My testing site is located at http://www.iemcal.com/webtest

Leave a Reply