Welcome to irritatedVowel.com Sign in | Help

POKE 53280,0: Pete Brown's Blog

Silverlight, WPF, Woodworking, .NET Programming, CNC, Nature, and other topics.

Pete Brown writes on a number of topics including Silverlight, WPF, .NET, woodworking and working as a consultant in the DC area. On most forums, Pete goes by the name Psychlist1972. Pete has worked at Applied Information Sciences (AIS) since 1996 where he currently performs as a lead architect and project manager.

Subscribe to my feed

Add to Technorati Favorites
Applied Information Sciences - My Employer

Community Events




World Domination

who's online

Networks


View Pete Brown's profile on LinkedIn

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

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.

  Add to Technorati Favorites
Posted: Monday, June 30, 2008 11:26 PM by Pete.Brown
Filed under: , ,

Comments

Christopher Steen said:

Link Listing - June 30, 2008
# July 1, 2008 6:29 AM

Christopher Steen said:

ASP.NET How to use the IHttpAsyncHandler in ASP.NET [Via: Mads Kristensen ] SQL Server SQL SERVER -...
# July 1, 2008 6:30 AM

martin said:

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.
# July 1, 2008 6:31 AM

Dew Drop - July 1, 2008 | Alvin Ashcraft's Morning Dew said:

PingBack from http://www.alvinashcraft.com/2008/07/01/dew-drop-july-1-2008/
# July 1, 2008 8:27 AM

Community Blogs said:

16 posts today... yikes: Corrina Barber on Sparkling Client, Training CD update via Tim Heuer, Progressive
# July 2, 2008 2:32 AM

POKE 53280,0: Pete Brown's Blog said:

I was going to present an analogy using different types of cars, but more often than not, the analogy
# August 17, 2008 5:58 PM

Community Blogs said:

I was going to present an analogy using different types of cars, but more often than not, the analogy
# August 17, 2008 6:31 PM
Leave a Comment

(required) 

(required) 

(optional)

(required) 

Enter the text you see in the image:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS