Welcome to WindowsClient.net | Sign in | Join

Building ScePhotoViewer

ScePhotoViewer is a sample application designed as a reference for developers creating rich client-based multimedia viewing experiences in WPF. It's a fairly sophisticated WPF application which is more or less complete though several features are stubbed out as placeholders.

The first section of this document is an overview of how the ScePhotoViewer application was developed using the Syndicated Client Experiences (SCE) Starter Kit. The second section is an overview of how we built ScePhotoViewer features such as setup, sync, effects, etc. Read on to learn more about how we created ScePhotoViewer and how you can leverage the innovations in ScePhotoViewer to build great experiences in your own applications.

Using the SCE Starter Kit to build a Media Viewer (ScePhotoViewer)

ScePhotoViewer was built using the Syndicated Client Experiences (SCE) Starter Kit SDK. The Syndicated Client Experiences (SCE) Starter Kit is a foundation for creating syndicated multimedia experiences for any type of media, including text, images, videos, and audio. The SCE Starter Kit was designed from the ground up to help WPF developers easily create rich, syndicated multimedia and content experiences to engage the end user. The sample application included in the SCE \Starter Kit SDK (SceReaderSample) is optimized for reading text content, so the first step in building ScePhotoViewer was to convert this sample into the ScePhotoViewer sample.

If you’d like to learn more about the SCE Starter Kit, please check out the following resources:

  1. Getting Started with the SCE Starter Kit contains instructions for getting your development environment set up, downloading and running the Starter Kit, and FAQs.
  2. SCE Starter Kit Architecture explains the architecture in detail. It describes the key classes and concepts used by the Starter Kit.
  3. Data Feed Spec describes how the data feeds are constructed.

Basic Architecture of the Starter Kit

First let's look at the pieces that make up the SCE Starter Kit. The following diagram illustrates the architecture of the SCE Starter Kit.

Building ScePhotoViewer

Data comes down to the client via a Data Feed. Then the data passes to the Data Converters where it is transformed from XML-based feeds into data objects that are consumed by the UI Layer. The UI Layer is an abstraction between the data and the application itself. It understands the structure of the data and how to display it and navigate through it. The Starter Kit Application can make calls to the UI Layer based on user interaction with the XAML controls and the UI Layer passes the correct data to the Application for display.

In the SCE Starter Kit sample application (SceReaderSample), the data is news stories, but this same model can be applied to any number of multimedia experiences, including photos.

The Data Feed

The data feed for the Starter Kit is based on RSS 2.0. The content from the NITF-based XML documents is grouped into a larger set of related items (see Data Feed Spec for more information). In the case of ScePhotoViewer, the data feed was generated from photos in a web-based photo service. ScePhotoViewer uses a FeedConverter to create the expected XML feed format.

SceReader has a base type that is the individual story. Each story has properties such as a headline, date, byline, body, etc. ScePhotoViewer has an individual photo feed which corresponds to the story in the data hierarchy. The FeedConverter in ScePhotoViewer takes the data from an RSS feed generated by a web-based photo service and converts it into the XML format which can be read by the Data Converter. The photo also has properties such as title, description, date, etc. You can see that you have similar properties for the photo and the story – title instead of headline, pubDate instead of dateline, etc. In addition, the photo has some properties which are unique, such as the hyperlink to the photo.

In addition to the individual data type, each application creates larger feeds that contain links to the individual feeds. In the SceReader, the larger feeds are called editions which contain sections and subsections that point to story feeds. There is also the concept of a master feed which points to the editions. In ScePhotoViewer there are gallery feeds which contain albums that point to individual photos.

It was necessary to define the feeds for each data type and their aggregates (e.g. photo, album, and gallery). Once the feed data formats were created, then the data converters needed to be modified to read in the feeds.

Data Converters

The data is read in by DataFeedSource.cs and passed to the data converters. The data converters take the XML feeds and put the data into the data objects that are used by the UI Layer. The converters are adjusted so that a story is now a photo, a section is now a photo album, etc. While the data sources and outputs are different, the logic that reads in the data is very similar. For example, let's look at the code that reads in the RSS feed and converts it to the data feed:

    // rx:stories
    childNavigator = navigator.SelectSingleNode("rx:stories", Nsmgr);
    if (childNavigator != null)
    {
       stories = GetGuidsFromNavigator(childNavigator, "story");
       if (stories.Count == 0)
       {
          isDataValid = false;
       }
     }

    // Photo Tags
    childNavigator = navigator.SelectSingleNode("media:category",
        this.NamespaceManager);
    string tags = GetTextFromNavigator(childNavigator);

In both cases, a navigator, which is an instance of XpathNavigator, is being called. The navigator is pulling out a single node from the feed. The methods GetGuidsFromNavigator and GetTextFromNavigator are defined in the converter classes but are simply using XPath navigation to traverse the navigator node and pull out the desired data.

Data Objects

The data converters place the data into the data objects. Each data object that is used in the application needs to be defined. For example, the SceReader contains the Story class while ScePhotoViewer contains the Photo class. These classes define the methods and properties necessary to contain and interact with the data. You can see these two classes summarized below.

Building ScePhotoViewer

Data objects must be created for each type of data the application intends to display, along with collection objects that will contain the types.

View Manager

The ViewManager.cs class contains the concept of active items which are currently being displayed in the application. The SCE Starter Kit has the ActiveStory and ActiveSection classes. For ScePhotoViewer, these were modified to become ActivePhoto and ActivePhotoAlbum.

Navigator

The navigation logic is updated in ScePhotoViewer to take into account changes in the data structure. For example, in SceReader sections can contain other sections, but in ScePhotoViewer photo albums cannot contain other photo albums. For this reason, some of the recursive searching was removed for efficiency. In general, though, most of the generic navigation code is reused (for example, NavigateToStoryCommand became NavigateToPhotoCommand). Looking at the definitions for these classes, they both derive from NavigationCommand and override PerformNavigate, where they call ViewManager.NavigateByCommand.

From SceReader\View\NavigationCommands.cs

    public class NavigateToStoryCommand : NavigationCommand
      {
      …
       protected override void PerformNavigate(object parameter)
       {
          StoryNavigator storyNavigator = parameter as StoryNavigator;
          if (storyNavigator != null)
          {
             ViewManager.NavigateByCommand(storyNavigator, 
                SceReaderNavigationMode.Normal);
          }
       }
      }

From ScePhoto\View\NavigationCommands.cs

    public class NavigateToPhotoCommand : NavigationCommand
        {
            …
            protected override void PerformNavigate(object parameter)
            {
                PhotoNavigator photoNavigator = parameter as PhotoNavigator;
                if (photoNavigator != null)
                {
                    ViewManager.NavigateByCommand(photoNavigator, ScePhotoNavigationMode.Normal);
                }
                else
                {
                    …
                }
            }
        }

The Control Authoring Overview is a good resource for help with creating new controls, such as the ScePhotoViewer controls that were created to handle displaying photos and groups of photos and to allow user interaction with them.

Creating the ScePhotoViewer Features

Once the Data Feed and the Starter Kit Core are updated, it's time to update the UI and turn it into ScePhotoViewer.

Sync

As explained above, content is read into SCE applications by way of a rich RSS2.0 feed. For ScePhotoViewer, we extended the basic RSS feed with CSX extensions for hierarchical RSS items (e.g. Gallery, Albums, Photos) supporting both the UI structure as well as intelligent sync logic, FeedSync extensions for enabling bi-directional sync (e.g. comments, ratings), Media RSS standard for media-based RSS (a la Flickr/Yahoo), and NITF (News Industry Text Format) standard. In this example, we have created an RSS feed with a utility that talks to Flickr's API to read in a stream of photos from a Flickr account.

Content is synched down to the local machine from the cloud for high performance navigation as well as offline access, creating a robust content viewing experience. The Subscription Center service runs in the background to sync “subscription” content from SCE apps even when the app isn’t running. This means that the user’s content will always be up to date. Content is (optionally) stored in a SQL Compact Edition database which is private to the application, and credentials can be stored for offline access to authenticated feeds.

Building ScePhotoViewer

The photos which appear in the Details view of ScePhotoViewer’s subscription in Subscription Center are specified as items in the master feed:

    <rss version="2.0" xmlns:csx="http://schemas.microsoft.com/rss/2007/contentsyncextensions" 
        xmlns:media="http://search.yahoo.com/mrss" 
        xmlns:sx="http://feedsync.org/2007/feedsync">
      <channel>
        <title>ScePhotoViewer Master Feed</title>
        <description />
        <link />
        <pubDate>8/21/2008 11:31:03 AM</pubDate>
        <lastBuildDate>8/21/2008 11:31:03 AM</lastBuildDate>
        <item csx:hiddenItem="true">
          <title>wpfphotos</title>
          <description />
          <link>http://www.flickr.com/photos/24218090@N03/</link>
          <guid isPermaLink="false">24218090@N03</guid>
          <pubDate>8/21/2008 11:31:03 AM</pubDate>
          <csx:lastBuildDate>8/21/2008 11:31:03 AM</csx:lastBuildDate>
          <csx:link nestedFeed="true">pc_24218090@N03.xml</csx:link>
        </item>
        <item>
          <title>Fields of Hay</title>
          <description>Hay is grass or legumes that has been cut, dried, and stored for 
            use as animal feed, particularly for grazing animals like cattle, horses, 
            goats, and sheep. Small pets such as guinea pigs and rabbits …</description>
          <link>http://www.flickr.com/photos/24218090@N03/2556304785/</link>
          <guid isPermaLink="false">2556304785</guid>
          <pubDate>8/9/2003 5:53:47 PM</pubDate>
          <csx:lastBuildDate>8/6/2008 8:51:57 PM</csx:lastBuildDate>
        </item>
        <item>
          <title>Apocalyptical Yellowstone</title>
          <description>Yellowstone National Park, set aside as a national park on 
            March 1, 1872, is located mostly in the U.S. state of Wyoming, though it 
            also extends into Montana and Idaho. The park was the 
            first of its k…</description>
          <link>http://www.flickr.com/photos/24218090@N03/2567415751/</link>
          <guid isPermaLink="false">2567415751</guid>
          <pubDate>5/5/2007 10:29:08 AM</pubDate>
          <csx:lastBuildDate>8/6/2008 8:52:26 PM</csx:lastBuildDate>
        </item>
        <item>
          <title>Grand Canyon South Rim</title>
          <description>The Grand Canyon is a steep-sided gorge carved by the Colorado 
            River in the U.S. state of Arizona,and parts of Nevada. 
            It is largely contained within the Grand Canyon National Park — 
            one of the first …</description>
          <link>http://www.flickr.com/photos/24218090@N03/2567415367/</link>
          <guid isPermaLink="false">2567415367</guid>
          <pubDate>4/28/2007 11:13:09 AM</pubDate>
          <csx:lastBuildDate>8/6/2008 8:52:44 PM</csx:lastBuildDate>
        </item>
      </channel>
    </rss>

Dynamic Layout

The dynamic layout of the galleries and albums in ScePhotoViewer was created using adaptive templates to enable pixel-perfect presentation scaling to screens of all sizes. When the window is resized, UI elements will flow and resize, and at specific thresholds defined by the UI designer, the app will switch layout templates. Authoring these templates is straightforward and part of the basic architecture of the Starter Kit SDK.

Building ScePhotoViewer
Building ScePhotoViewer
Building ScePhotoViewer
Building ScePhotoViewer
Building ScePhotoViewer

You can learn more about customizing these templates in "How To: Customizing Section Fronts." In ScePhotoViewer, the templates for the Gallery Home are applied in the GalleryHomeResources.xaml file.

    <!-- Collection of templates to use for the gallery home control, 
        depending on the amount of space available -->
    <ScePhotoControls:SizeControlTemplateCollection x:Key="GalleryHomeTemplateCollection">
      <ScePhotoControls:SizeControlTemplate MinWidth="0" MinHeight="0" MaxWidth="800" 
        MaxHeight="350" Template="{StaticResource GalleryHome_MiniList}" />
      <ScePhotoControls:SizeControlTemplate MinWidth="300" MinHeight="350" MaxWidth="1000"  
        Template="{StaticResource GalleryHome_Tall}" />
      <ScePhotoControls:SizeControlTemplate MinWidth="800" MaxHeight="455"  
        Template="{StaticResource GalleryHome_Tall}" />
      <ScePhotoControls:SizeControlTemplate MinWidth="1000" MinHeight="450" MaxHeight="650" 
        Template="{StaticResource GalleryHome_Wide}" />
      <ScePhotoControls:SizeControlTemplate MinWidth="1000" MinHeight="650" MaxHeight="800" 
        Template="{StaticResource GalleryHome_Medium}" />
      <ScePhotoControls:SizeControlTemplate MinWidth="1000" MinHeight="800"  
        Template="{StaticResource GalleryHome_Large}" />
    </ScePhotoControls:SizeControlTemplateCollection>

Navigation

Effortless and intuitive navigation gestures and super-fast navigation performance were high priorities for ScePhotoViewer. The high performance navigation in ScePhotoViewer was accomplished using some innovative techniques, including:

  • Worker thread pool: ThreadPool, which comes with .NET, executes all threads with the same priority (Normal). Since normal priority is also used for all UI processing, that could result in a negative impact on performance. For this reason, we developed our own worker thread pool which adds the possibility to change the thread priority. All network and file IO operations are run with the lowest priority in SCE apps.
  • Event-based async pattern: For any potentially expensive operation, we execute in asynchronous mode. For all asynchronous operations we are extensively using event-based async pattern and cancelation functionality. If an operation is initiated and then becomes unnecessary due to user action (for example, a navigation request) we cancel the operation to avoid unnecessary work.
  • XML data loading and conversion is done asynchronously: Background worker threads (worker thread pool) are used when loading XML files and converting those to the data model.
  • Image loading and processing is done asynchronously: Background worker threads (worker thread pool) are used when loading image files and decompressing them (converting to BitmapImage).
  • Requesting data when UI is initialized: During navigation, UI is initialized without binding it directly to actual data. Then after UI initialization is completed, data is requested asynchronously.
  • Priority queues for network access: When accessing network resources (HttpWebRequest) we have priority queues that control the order of execution requests. Requests associated with UI are executed as high priority.

Search and Tag Explorer

With data binding, templates and styles, WPF makes it really easy to create new experiences reusing the same business logic. The different views in ScePhotoViewer are examples of this. The spider-like Tag Explorer view allows the user to “surf” the same metadata that the default photo viewing mode uses to create the UI. All of this metadata is included in the content feed and the feed can be easily modified to include many different types of metadata, from comments and ratings, to file sizes and photo formats.

Building ScePhotoViewer

In ScePhotoViewer, the SearchViewControl.xaml and SearchViewControl.xaml.cs files contain the implementation of the search control and tag explorer. The PhotoExplorerControl class in ScePhoto defines some properties (such as CoefficientOfDampening or LinePen) which can be used to customize the look and behavior of the tag explorer, and the commands for switching nodes.

    /// <summary>
    /// Switches the current center node for the one passed in as a parameter.
    /// </summary>
    /// <param name="sender">The source of the event.</param>
    /// <param name="e">Arguments describing the routed event.</param>
    private static void OnSwitchCenterNodeCommand(object sender, 
        ExecutedRoutedEventArgs e)
    {
        PhotoExplorerControl photoExplorer = sender as PhotoExplorerControl;
        PhotoExplorerBaseNode nextNode = e.Parameter as PhotoExplorerBaseNode;

        if (photoExplorer != null && nextNode != null)
        {
            if (nextNode == photoExplorer.CenterNode)
            {
                PhotoExplorerPhotoNode photoNode = photoExplorer.CenterNode as 
                    PhotoExplorerPhotoNode;
                if (photoNode != null)
                {
                    ServiceProvider.ViewManager.NavigationCommands.
                        NavigateToPhotoCommand.Execute(photoNode.PhotoNavigator);
                }
            }
            else
            {
                photoExplorer.CenterNode = nextNode;
            }
        }
    }

Shader Effects

In .NET 3.5 SP1, we added the ability to create custom hardware accelerated bitmap/shader effects. ScePhotoViewer demonstrates a few of these effects in the "FX" panel and in the Slideshow transitions. Effects can be applied to other elements (e.g. video) or to the entire UI, and hit testing, navigation, and other functions will still work normally. In ScePhotoViewer, a blur effect has been applied to the photo filmstrip to create a nice navigation effect as you zip through photos. Some 20 sample effects are included in the ScePhotoViewer source, and it’s also straightforward to author custom effects.

Building ScePhotoViewer

Sample effects can be found in the TransitionEffects and EffectsLibrary projects which are included with the ScePhotoViewer source code. You can learn more about building your own shader effects on WindowsClient.net or the WPF Codeplex site.

Reading Mode

ScePhotoViewer also takes advantage of one of WPF’s other great strengths: typography. This application demonstrates some of the advanced text and typography features including OpenType, ligatures, ClearType, and Flow/Pagination. Application authors can utilize these features to create highly designed, distinctive user interfaces. Fonts can be built into the resources of such that they are private to the application, but can still be viewed even on computers which do not have that particular font installed.

Building ScePhotoViewer

The articles "How To: Customizing the Appearance of Articles" and "How To: Using Fonts with the SCE Starter Kit" provide more information about customizing the reading mode.

Setup

Finally, one of the most exciting features in ScePhotoViewer is the new install and update experience. ScePhotoViewer is our showcase application for the deployment improvements made in .Net 3.5 SP1, including a branded installer created using our new Configuration utility for custom, optimized install experiences. With only three clicks, one window, and under eight minutes from download to launch on a clean Windows XP machine with a typical broadband connection (and as little as three minutes on a faster connection), this the best install experience created with the .NET Framework yet. A lot of improvements went into creating this deployment experience, including:

  • A smaller, faster NET Framework redistributable. The .NET Framework Client Profile is only about 28 mb in size and setup optimizations were devised for NGen and downloading.
  • Brandable deployment experience. Developers can customize their app deployment experience to match their brand instead of using a generic installer window.
    Building ScePhotoViewer
  • Easier deployment of applications. Developers can now use a deployment bootstrapper to manage the installation of their application and pre-requirements. The bootstrapper will install the application after the Framework and launch it.
  • ClickOnce. Including added support for FireFox and seamless app update with no ClickOnce UI necessary, ClickOnce has raised the bar for update experiences. The application will check for an update in the background (with no impact on startup performance) and if an update is found, it will be installed in the background. Upon application restart, the updated app is invoked, or developers can choose to optionally prompt the user and restart or refresh automatically, replicating a web application in terms of seamlessness of update.

ClickOnce in .NET 3.5 or later also supports arguments, which allows ScePhotoViewer to pull up specific photos via the Subscription Center details view. This also enables users to pass around URLs to specific pieces of content in the application (images in this case). If the application is not installed, ClickOnce can be invoked to install it.

Learn More

Install the full ScePhotoViewer source code here and read more about customizing your own SCE application here. You can also install the ScePhotoViewer sample application here.

Featured Item