Welcome to Pete Brown's 10rem.net

First time here? If you are a developer or are interested in Microsoft tools and technology, please consider subscribing to the latest posts.

You may also be interested in my blog archives, the articles section, or some of my lab projects such as the C64 emulator written in Silverlight.

(hide this)

Using Pub/Sub and the Observer Pattern in Silverlight 2 (Part 2 of 2) Navigation

Pete Brown - 30 June 2008

In the previous two parts of this article (I had planned only 2 parts total, but this ended up a three-part article), I explained how to use Pub/Sub and the EventBus for chaining service calls in Silverlight 2 applications. You can access those articles here:

In this part, I'll cover how I use this same pattern for UI navigation in a Silverlight application.

Problem

You have multiple "screens" in the application and you can navigate to them in a variety of ways. For example, Screen 1 could contains links to screens 2, 3 and 4 and Screen 6 could contain a link back to Screen 3. Add to that the idea that a couple of the screens screens could, say, pop up a media player overlay and you see where the code could get messy quickly.

image

A Little Background

It may help visualize this a bit if I describe the UI in the application I'm building. The application has the following screens at this point:

  • Home Screen
    • Subset of Events Listing and link to Events Page
    • Subset of Blog Listing and link to Blogs Page
    • Subset of Media List and link to Media Page
    • Link to play a featured video (shows media player overlay)
  • Events Listing Page
    • List of local events
  • Blog Listing Page (General Page)
    • List of blog posts
  • Media Listing Page
    • Videos and screencasts
    • Link to show Media Player overlay
  • User Options Page
    • Various options the user can set
  • Media Player Overlay
    • Slides out over current content and plays a video.
  • Loading Screen
    • Last screen in the slider. Just contains a “loading” animation

The implementation of the screens is interesting. Home, Events, Blog, Media, Loading and Options are all contained in a single stack panel that slides right or left on the screen to bring the selected screen into focus. Think of it like a filmstrip, or a simple 2d carousel (but with hard stops at the end) containing screens.

When the application goes live, I’ll post a link here and you’ll be able to see the animation in action. It was pretty simple to do:

<UserControl x:Class="AppliedIS.PartnerHuddle.Screens.PageScroller"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:screens="clr-namespace:AppliedIS.PartnerHuddle.Screens"
    Width="640" Height="400">

    <UserControl.Resources>
        <Storyboard x:Name="ScrollToPageStoryboard">
            <DoubleAnimationUsingKeyFrames 
                BeginTime="00:00:00" 
                Storyboard.TargetName="PageContainer" 
                Storyboard.TargetProperty="(Canvas.Left)">
                <SplineDoubleKeyFrame 
                    KeyTime="00:00:00.8000000" 
                    Value="0" x:Name="ScrollToPageStoryboardTargetX">
                    <SplineDoubleKeyFrame.KeySpline>
                        <KeySpline ControlPoint1="0,0.009" 
                                   ControlPoint2="0,0.989"/>
                    </SplineDoubleKeyFrame.KeySpline>
                </SplineDoubleKeyFrame>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </UserControl.Resources>

    <Grid x:Name="LayoutRoot">
        <Canvas Width="600" Height="400">
            <StackPanel Orientation="Horizontal" x:Name="PageContainer" 
                        Canvas.Left="0">
                <screens:HomePage x:Name="HomePage" />
                <screens:EventsPage x:Name="EventsPage" />
                <screens:MediaPage x:Name="MediaPage" />
                <screens:GeneralPage x:Name="GeneralPage" />
                <screens:UserSettingsPage x:Name="UserSettingsPage" />
                <screens:DataLoadingPage x:Name="DataLoadingPage" />
            </StackPanel>
            
            <Canvas.Clip>
                <RectangleGeometry Rect="0 0 600 400" />
            </Canvas.Clip>
        </Canvas>            
    </Grid>
</UserControl>

Here’s a subset of the scroller code in the scrolling screen container/panel:

private void ScrollToPage(UserControl page)
{
    int i = PageContainer.Children.IndexOf(page);

    if (i < 0)
    {
        throw new ArgumentException("Specified page is not contained in the scrollable container.", "page");
    }
    else
    {
        double currentPosition = 
            (double)PageContainer.GetValue(Canvas.LeftProperty);
        double newPosition = i * page.Width *-1;    // ASSUMPTION: All pages are the same width


        if (ScrollToPageStoryboard.GetCurrentState() == ClockState.Active)
            ScrollToPageStoryboard.Stop();

        // build storyboard to scroll to that page
        ScrollToPageStoryboardTargetX.Value = newPosition;
        ScrollToPageStoryboard.Begin();

    }
}

 

My Solution - A Specialized Event Bus

I don't deal with data here at all, this is solely a navigation and screen presentation pattern, so I'm not offering up a full MVC (or MVP) solution. I have nothing against MVC, I just decided against building that type of framework for this application (and some others) I've built. Those patterns are also much more comprehensive than what I have here. That said, I certainly borrowed some concepts.

The other point I'd like to make is that this solution does not attempt to solve the "can screen x be shown now" problem yet.

image

In the diagram, I left out the lines connecting the scrolling screen container from the screens themselves, as that would just be clutter. Those lines will become more important in the future when I add in events to indicate when the screen is actually displayed, and when we are about to nav off the screen (for validation purposes)

// This enum needs to contain all possible nav targets for the application
public enum NavigationScreenTarget
{
    LoadingScreen,
    HomePage,
    EventsPage,
    MediaPage,
    GeneralPage,
    UserOptionsPage
}

// Event arguments for the navigation events
public class NavigationEventArgs : EventArgs
{
    private NavigationScreenTarget _target;
    private bool _instantaneous = false;

    public NavigationEventArgs(NavigationScreenTarget target, bool instantaneous)
    {
        _target = target;
        _instantaneous = instantaneous;
    }

    public NavigationScreenTarget Target
    {
        get { return _target; }
    }

    public bool InstantaneousNavigation
    {
        get { return _instantaneous; }
    }

}

// Navigation controller class
public static class NavigationController
{
    public static event EventHandler<NavigationEventArgs> NavigateToScreen;
    public static event EventHandler ShowMediaPlayer;
    public static event EventHandler HideMediaPlayer;


    // This tell the target to navigate to the screen using
    // the default behavior (animated, typically)
    public static void NotifyNavigateToScreen(NavigationScreenTarget target)
    {
        NotifyNavigateToScreen(target, false);
    }

    // this tells the target to navigate to the screen with no
    // transition animation
    public static void NotifyNavigateToScreen(
        NavigationScreenTarget target, bool instaneous)
    {
        if (NavigateToScreen != null)
            NavigateToScreen(null, 
                new NavigationEventArgs(target, instaneous));
    }


    // specialized navigation events

    public static void NotifyShowMediaPlayer()
    {
        if (ShowMediaPlayer != null)
            ShowMediaPlayer(null, new EventArgs());
    }

    public static void NotifyHideMediaPlayer()
    {
        if (HideMediaPlayer != null)
            HideMediaPlayer(null, new EventArgs());
    }


}

In this case, I called the class NavigationController. Other names like ScreenPresenter would certainly seem to fit. I haven’t come up with a reasonable name that doesn’t imply MVC/MVP, so if you come up with something, be sure to post it in the comments here.

I used the word “Notify” instead of “On” for the method names as this was an instructional event, as opposed to informational. I could have gone all old windows and called it “PostXEvent” or something, but that just didn’t feel right either.

I also included an example of a specialized event (NotifyShowMediaPlayer). I did that one differently from the normal navigation because it is an overlay “window”, not a real navigation target in the scrolling screen container.

When this project is complete, I’ll extract the interesting bits, like this, and post an end-to-end example that uses the Navigation, EventBus, Scroller, and other bits. In the mean time, I hope these three posts have given you some ideas for how to handle navigation and async communications in your own applications.

     
posted by Pete Brown on Monday, June 30, 2008
filed under:      

1 comment for “Using Pub/Sub and the Observer Pattern in Silverlight 2 (Part 2 of 2) Navigation”

  1. martinsays:
    Windows Media Player 11 has been completely redesigned it now brings a completely new look and feel to your entertainment suite. One of the main problems with previous versions of Windows Media Player was that it didn’t include a DVD Decoder. Fantastic article.I found the article very interesting.

Comment on this Post

Remember me

9 trackbacks for “Using Pub/Sub and the Observer Pattern in Silverlight 2 (Part 2 of 2) Navigation”

  1. Silverlight news for July 1, 2008 says:
    PingBack from http://www.silverlightshow.net/news/Silverlight-news-for-July-1-2008.aspx
  2. Christopher Steensays:
    ASP.NET How to use the IHttpAsyncHandler in ASP.NET [Via: Mads Kristensen ] SQL Server SQL SERVER -...
  3. Dew Drop - July 1, 2008 | Alvin Ashcraft's Morning Dewsays:
    PingBack from http://www.alvinashcraft.com/2008/07/01/dew-drop-july-1-2008/
  4. Community Blogssays:
    16 posts today... yikes: Corrina Barber on Sparkling Client, Training CD update via Tim Heuer, Progressive
  5. POKE 53280,0: Pete Brown's Blogsays:
    I was going to present an analogy using different types of cars, but more often than not, the analogy
  6. Community Blogssays:
    I was going to present an analogy using different types of cars, but more often than not, the analogy
  7. POKE 53280,0: Pete Brown's Blogsays:
    My primary Silverlight project for the past couple months has been the Facebook application I’ve been
  8. ibillguosays:
    前提条件:阅读本文之前请确认你已经安装了如下软件VisualStudio2008(Express)SP1Silverlight3ToolsForVisualS...