electric beach

Christian Schormann

Tuesday, September 1, 2009

SketchFlow: Conditional Navigation Behavior Sample

Yesterday, somebody asked me how to do conditional navigation in SketchFlow. Out of the box, there is no built-in behavior to do conditional navigation, but the good news is that it is not hard to write one. Here is an example for how to do it.

There are many different ways of doing it. For this sample, it works like this:

  • There are two behaviors: SetNavigationTarget and ConditionalNavigation
  • SetNavigationTarget takes one property that you set to the display name of the screen you want to navigate to the next time ConditionalNavigation is triggered. You can have as many of these behaviors as you want across your screen – the last one triggered wins.
  • ConditionalNavigation navigates to the screen set by the last triggered SetNavigationTarget behavior.

Before I explain the code, here is a screenshot of a minimal sample app using them:

CondNav 

The app has two instances of the SetNavigationTarget behavior. One is attached to the LayoutRoot and set to fire right after loading:

DefaultSetTarget

It sets the target screen to “Screen 2”. It is generally a good idea to have one SetNavigationTarget behavior triggered by the Loaded event on every page where you want a default target to be set.

The second instance is attached to the toggle button, and sets the target screen to “Screen 3” when the toggle button is checked.

Finally, the “Navigate!” button on the page has the ConditionalNavigation behavior attached to it, fired by a click of the button.

About the Code

Both behaviors use a little backend object to store state:

   1: public class NavigationTargetStore

   2: {

   3:     private static NavigationTargetStore instance;

   4:

   5:     protected NavigationTargetStore()

   6:     {

   7:     }

   8:

   9:     public static NavigationTargetStore Instance

  10:     {

  11:         get

  12:         {

  13:             if (instance == null)

  14:                 instance = new NavigationTargetStore();

  15:             return instance;

  16:         }

  17:     }

  18: 

  19:     public string TargetScreen

  20:     {

  21:         get;

  22:         set;

  23:     }

  24: }

This backend object is a singleton. That is, an object that can only be instantiated once, and that is accessible through a global static access property. This is a very simple singleton – all it offers is a single string property to store the desired name of the Target screen.

The SetNavigationTarget behavior is also quite simple: Whenever it is triggered, it just stores the string set as its property in the backend object:

   1: public class SetNavigationTarget : TriggerAction<DependencyObject>

   2: {

   3:     public SetNavigationTarget()

   4:     {

   5:         // Insert code required on object creation below this point.

   6:     }

   7: 

   8:     protected override void Invoke(object o)

   9:     {

  10:         // Insert code that defines what the Action will do when triggered/invoked.

  11:         NavigationTargetStore.Instance.TargetScreen = this.TargetScreen;

  12:     }

  13: 

  14:     public string TargetScreen

  15:     {

  16:         get { return (string)GetValue(TargetScreenProperty); }

  17:         set { SetValue(TargetScreenProperty, value); }

  18:     }

  19: 

  20:     // Using a DependencyProperty as the backing store for TargetScreen.  This enables animation, styling, binding, etc...

  21:     public static readonly DependencyProperty TargetScreenProperty =

  22:         DependencyProperty.Register("TargetScreen", typeof(string), typeof(SetNavigationTarget), new PropertyMetadata(""));

  23: 

  24: }

ConditionalNavigation is not really complicated either, but it does have a little twist:

The API function of the player that navigates between screens requires the class name of the screen including its namespace to work. However, this is not the name shown in the SketchFlow Map (you might have renamed the screen, but at the very least, the displayed name is without the name space). In the Invoke() method, there is a little bit of code that walks through all screens present in the prototype and checks if one matches the “nickname” given to the behavior. If it does, the behavior navigates to that screen happily. Otherwise, it does nothing.

   1: public class ConditionalNavigation : TriggerAction<DependencyObject>

   2: {

   3:     public ConditionalNavigation()

   4:     {

   5:         // Insert code required on object creation below this point.

   6:     }

   7: 

   8:     protected override void Invoke(object o)

   9:     {

  10:         // Insert code that defines what the Action will do when triggered/invoked.

  11:         string screen = NavigationTargetStore.Instance.TargetScreen;

  12:         if (screen == null || screen == "")

  13:             return;

  14:         List<Serializer.Data.Screen> screens = PlayerContext.Instance.RuntimeData.Screens;

  15:         foreach (Serializer.Data.Screen ds in screens)

  16:         {

  17:             if (ds.DisplayName == screen)

  18:                 PlayerContext.Instance.ActiveNavigationViewModel.NavigateToScreen(ds.ClassName, true);

  19:         }

  20: 

  21:     }

  22: }

Finally, here is the sample project with the sample source code for the two behaviors:
ConditionalNavigationSample.zip

posted by cs at 14:22  

3 Comments

  1. [...] This post was Twitted by MSExpression [...]

    Pingback by Twitted by MSExpression — September 2, 2009 @ 11:47

  2. [...] more here [...]

    Pingback by SketchFlow: Conditional Navigation Behavior Sample | Silverlight Travel — September 4, 2009 @ 23:52

  3. [...] The Conditional Navigation behaviors enables you to navigate to a different screen based on a TargetScreen variable that is set using events in the interface. [...]

    Pingback by SketchFlow Behavior CheatSheets « ADdendum — September 28, 2009 @ 06:55

RSS feed for comments on this post. TrackBack URI

Sorry, the comment form is closed at this time.

Powered by WordPress