Welcome to irritatedVowel.com Sign in | Help

POKE 53280,0: Pete Brown's Blog

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

Subscribe

Subscribe to my feed
Add to Technorati Favorites

My Book

Order my upcoming book, Silverlight in Action, covering Silverlight 4, ViewModel/MVVM, WCF RIA Services, MEF and more

About Pete Brown

Pete Brown is a Microsoft Developer Division Community Program Manager, focusing on Windows Client Development as well as a former Microsoft Silverlight MVP and INETA Speaker. Pete writes on a number of topics including Silverlight, WPF, .NET, woodworking and working as a consultant in the DC area. read more

Community Events


who's online

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

Silverlight news for July 1, 2008 said:

PingBack from http://www.silverlightshow.net/news/Silverlight-news-for-July-1-2008.aspx
# July 1, 2008 5:05 AM

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

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

My primary Silverlight project for the past couple months has been the Facebook application I’ve been
# September 21, 2008 2:26 AM

ibillguo said:

前提条件:阅读本文之前请确认你已经安装了如下软件VisualStudio2008(Express)SP1Silverlight3ToolsForVisualS...
# March 31, 2009 4:30 AM
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