LionHeart & World Autism Awareness Day 2013

LargePC

Today holds a special place in my heart. For the last 3 years my wife has been working with children with Autism helping them to overcome and manage behaviors that are reactive, inappropriate, and distracting to themselves and others. Her kids are amazing little creatures! While some are severely impacted many are not. They are so sweet and love making her get well cards when she is out. It’s impressive. Certainly I can never hope to achieve such satisfaction in my job as a software engineer. However, I can definitely try to help!

Introducing LionHeart: Autism Behavior Interventionist Assistant

It is with great pleasure that I bring you LionHeart; a proof of concept aid for Behavior Interventionists delivering services to people with Autism. The concept of LionHeart came from my wife while we were discussing ways software could help influence medicine. She explained that her job as an Interventionist consists of going home to home to visit each child for a few hours. During the session she uses ABA therapy to help the child learn appropriate behaviors. First the Interventionist reviews notes from the previous session. Then during the session the Behavior Interventionist will keep tally of behaviors and responses. After the session the Interventionist records qualitative notes in the child’s record binder. Every month the binder is collected and paper records are read and transferred to different paper records. It’s a very tedious job. The binder is then hopefully returned to the child’s home before their next session. If not, the Interventionist will have little to no idea how that child is progressing and how to proceed. Even with the binder, there is no easy way to see the child’s improvement over time in a specific program without reading weeks of session notes. Because it is so difficult to see progress over time it is rarely if ever done in the field.

LionHeart is the solution. The app provides a hint at what digital records could look like. It also gives an idea of how easy it would be to generate reports in the office let alone in the field. The concept is that each Interventionist would have a device, like a smart phone or tablet, that would have an app like LionHeart installed. The app has the ability to track behavioral data, record session notes, review client progress, map client addresses, help keep Interventionists in the know about cancelled/postponed/rescheduled sessions, and more! What is currently an extremely inefficient system could be streamlined to benefit the client as well as the service provider.

Goal of LionHeart

My goal when I set out to create LionHeart was to show that technology can be used in simple ways to accomplish great things! My wife wishes she could use LionHeart in the work place, but that of course requires much more than a simple Demo app. I hope, in the near future, that Autism service providers will strive to adopt time saving and quality of care improving technology such as LionHeart. InterKnowlogy is a wealth of knowledge and I continue to be impressed by how well our team works to effectively deliver awesome and amazing software. I would love to see InterKnowlogy partner with Autism service providers to make LionHeart a reality!

Why the Name LionHeart?

The name itself is a fun little story. I had been contemplating a name for a few days for the project. The thought came to me that these kids have huge hearts. They are just so full of love. And while this thought ran through my head I was staring at a pad of paper my mother in-law had given me with a print of a lion on it. I realized lions have big hearts and these kids are often as wild as a lion. How fitting then to give the app the title of LionHeart representing both the challenges and rewards for working with children with Autism.

Screen Shots

List of Session & Viewing Session Info

1a_SessionList2_Session

List of Session Notes & List of Programs in a Session’s Notes

1c_SessionNotesList3b_SessionNotes_Programs

Client Information & Client Progress Over Time

4a_Client_Info4b_Client_Progress

Special Thanks

I would have never finished LionHeart with out the awesome support of the InterKnowlogy team and our RECESS time. You can learn about RECESS here. A special shout out to Beth Juncal who help me work with a designer to make the app beautiful. A huge thanks to Xen Rabara who came to InterKnowlogy in January as a fresh graduate from my alma mater Neumont University, and styled almost the entire app! Travis Schilling also helped me get in a crucial last minute revision to help with usability! Of course I want to thank the company Holly works for, C.A.S.E. Inc., and especially her boss, Cynthia Norall, who has helped me understand the challenges faced by Interventionists in the field. And finally my wife Holly who continues to impress me everyday in her care and love for children with Autism!

Development History

If you’re a developer interested in learning how to make a Windows Phone app like LionHeart check out this blog series on how LionHeart was created.

WP Simplified: Data Providers for Real vs. Mock Data

This post will bring closure to the framework components of my series WP Simplified. We’ll be covering, at very high level, how to architect data providers in Windows Phone 7.5 and a good pattern for supporting real and mock/design time data. I discuss storage options in a post about Tombstoning. Due to simplicity I’ve chosen to use IsolatedStorage for storage.

Object References

Let’s first discuss what the best approach for developing a data provider is. Understanding that each app is going to require a completely custom build data provider there is one rule that I feel very strongly about. That rule is that if you have a reference to an object that is stored in persistent storage you should not create a second reference to that object inside of the same app. In other words, when you ask a data provider for an object it should always return the same object and not a different instance. We ran into a huge problem with modifying the incorrect copy of an object due to the pattern we were following for navigation. I mentioned this problem in WP7 Simplified: CoreApplicationService (Navigation) under the section titled Lesson #1: Centralize Data.

So, what’s the solution? Cache objects in memory for the lifetime of the app and always return the same reference to an object from the cache if it exists or create a reference to an object and store it in cache. We found that using ReadOnlyObservableCollection<T> allowed us to be pretty flexible. In phone apps users are typically viewing lists of data or data from a list and they want to know immediately if new data is available. By using Observable Collections the list is automatically updated when new data is available. The reason for use ReadOnlyObservableCollections is so the data provider can hand off a collection to a VM and the VM will not be able to add any new items to that collection directly. Instead the VM must utilize the data provider for CRUD actions on the collection.

Data Provider in Lion Heart

We use Initialize rather than the Constructor in our PhoneDataProvider for data setup. This allowed us to think in one pattern for VMs and DataProviders rather than jumping around and forgetting when data is setup and where that logic lives. Until Initialize is called the data provider is not useful and will throw errors.

public class PhoneDataProvider : IDataProvider
{
	private static readonly string CLIENTS_KEY = "CLIENTS_KEY";
	private static readonly string SESSION_NOTES_KEY = "SESSION_NOTES_KEY";
	private static readonly string SESSIONS_KEY = "SESSIONS_KEY";

	private bool _isInitialized;
	private ObservableCollection<Client> _clients;
	private ObservableCollection<SessionNotes> _sessionNotes;
	private ObservableCollection<Session> _sessions;
	private ReadOnlyObservableCollection<Client> _clientsReadOnly;
	private ReadOnlyObservableCollection<SessionNotes> _sessionNotesReadOnly;
	private ReadOnlyObservableCollection<Session> _sessionsReadOnly;

	public void Initialize()
	{
		if (_isInitialized)
		{
			return;
		}

		if (!RetrieveValue(CLIENTS_KEY, out _clients))
		{
			_clients = new ObservableCollection<Client>();
		}
		if (!RetrieveValue(SESSION_NOTES_KEY, out _sessionNotes))
		{
			_sessionNotes = new ObservableCollection<SessionNotes>();
		}
		if (!RetrieveValue(SESSIONS_KEY, out _sessions))
		{
			_sessions = new ObservableCollection<Session>();
		}

		SaveChanges();
		_isInitialized = true;
	}
	
	private bool RetrieveValue<T>(string key, out T value)
	{
		return IsolatedStorageSettings.ApplicationSettings.TryGetValue(key, out value);
	}
	
	public void SaveChanges()
	{
		SaveValue(CLIENTS_KEY, _clients);
		SaveValue(SESSION_NOTES_KEY, _sessionNotes);
		SaveValue(SESSIONS_KEY, _sessions);
	
		Save();
	}
	
	private void SaveValue<T>(string key, T value)
	{
		IsolatedStorageSettings.ApplicationSettings[key] = value;
	}
}

A few important things to note here.

  1. Only Initialize if the data provider is not initialized.
  2. Retrieve collections from IsolatedStorage or create them if they do not exist. These collections are now the cache of objects that should be queried for the rest of the app lifetime.
  3. Call SaveChanges to persist any newly created collections. (This may or may not really be necessary.)

When a VM requires a collection of objects it must request that collection via a method. In LionHeart we will use Client as an example. To get the collection of Clients from the data provider the method GetClients must be used.

public class PhoneDataProvider : IDataProvider
{
	public ReadOnlyObservableCollection<Client> GetClients()
	{
		if (_clientsReadOnly == null)
		{
			_clientsReadOnly = new ReadOnlyObservableCollection<Client>(_clients);
		}
		return _clientsReadOnly;
	}
}

When a new object is created and needs to be added to a collection expose a method to handle this functionality. We do this with a new Client via the AddClient method.

public class PhoneDataProvider : IDataProvider
{
	public void AddClient(Client newClient)
	{
		if (newClient != null)
		{
			_clients.Add(newClient);
			SaveChanges();
		}
	}
}

Deleting an object should be handled the same way as add. LionHeart has no need for deleting so I don’t have any example to show.

Finally, if an existing object is modified the only action required is to call SaveChanges.

public class PhoneDataProvider : IDataProvider
{
	public void SaveChanges()
	{
		SaveValue(CLIENTS_KEY, _clients);
		SaveValue(SESSION_NOTES_KEY, _sessionNotes);
		SaveValue(SESSIONS_KEY, _sessions);
	
		Save();
	}
}

When modifying objects and calling SaveChanges on the data provider one might think of Entity Framework or LINQ to SQL. Those frameworks were actually used as inspiration for the data provider pattern used. It is important to know that LINQ to SQL is supported in Windows Phone 7.5 and I shamefully have had no time to look into using it. I fully admit that the data provider architecture in LionHeart could and probably be improved.

Real (Production) vs. Mock (Design) Data Providers

I had some help from Bryan Coon and Tim Askins coming up with a pattern that would easily support using Blend with mock data without the need for a bunch of crazy garbage code. In the first code snippet shown you’ll notice PhoneDataProvider implements the interface IDataProvider.

public interface IDataProvider
{
	void Initialize();
	void SaveChanges();
	void AddClient(Client newClient);
	void AddSessionNotes(SessionNotes newSessionNotes);
	void AddSession(Session newSession);
	Client GetClient(Guid clientId);
	Session GetSession(Guid sessionId);
	SessionNotes GetSessionNotes(Guid sessionNotesId);
	ReadOnlyObservableCollection<Client> GetClients();
	ReadOnlyObservableCollection<SessionNotes> GetSessionNotes();
	ReadOnlyObservableCollection<Session> GetSessions();
	Session GetSessionForSessionNotes(Guid sessionNotesId);
}

By doing this we open up the opportunity to use the Locator pattern. LionHeart includes DataProviderLocator which simply chooses which IDataProvider to hand out.

public class DataProviderLocator
{
	private static IDataProvider _dataProvider;
	public static IDataProvider DataProvider
	{
		get
		{
			if (_dataProvider == null)
			{
				if (DesignerProperties.IsInDesignTool)
				{
					_dataProvider = MockDataProvider.Instance;
				}
				else
				{
					_dataProvider = PhoneDataProvider.Instance;
				}
				_dataProvider.Initialize();
			}
			return _dataProvider;
		}
	}
}

In this case only two IDataProvider implementers exist: PhoneDataProvider and MockDataProvider. If the app is in a design tool then the MockDataProvider is used otherwise the PhoneDataProvider is used.

Now the only weird part, and I’m still trying to find a better way to do this, is setting up VMs for mock data. Usually the Initialize method of a VM is called to set it up with data, however Initialized will never be called in design tool. In this case we still must modify the VM we desire to use in Blend by adding a query to the DataProvider in the Constructor of the VM.

public class ClientPageVM : PageViewModel
{
	public ClientPageVM()
	{
		if (DesignerProperties.IsInDesignTool)
		{
			InitializeData(DataProviderLocator.DataProvider.GetClients().First().Id);
		}
	}
	
	private void InitializeData(Guid clientId)
	{
		Client = ViewModelFactory.CreateClientVM(DataProviderLocator.DataProvider.GetClient(clientId));
		...
	}
}

This code will only be run when the app is in a design tool so it’s safe to leave in. One could argue that it should be optimized out in release mode and I think that would not be a bad idea.

Something interesting to note here is that the InitializeData method is used as a single point of entry whether or not the app is in a design tool or not. There is a huge benefit to this. Reduced duplicated code. If the way the VM handles the client id changes, the updates only need to be applied in one location. DONE!

Conclusion

This post ends coverage of Framework Elements in LionHeart. The other cool part about finishing this post is the next step is to provide a project template that will provide all the Framework Elements discussed in this series automatically.

WP7 Simplified: PageViewModel, ViewBase, and Using CoreApplicationService

In this post continuing my series WP7 Simplified we’ll be covering the PageViewModel class. This ViewModel (VM) hides all of the complicated wiring up that is necessary to work with ViewBase as mentioned in my post WP7 Simplified: CoreApplicationService (Navigation). PageViewModel is an abstract class that acts as the base class for all VMs backing Views (aka Pages). The three key parts to this class are: Initialize, Uninitialize, and hooking into the CoreApplicationService (CAS).

Initialize

ViewModels need to be built up based on navigation parameters in Windows Phone. Because of this it is more flexible to use an Initialize and Uninitialize vs. Constructor and Dispose pattern. Derived VMs can be defined as the DataContext in the XAML of Views that inherit from ViewBase.

<Views:ViewBase x:Class="LionHeart.UI.Phone.Views.HomeView"
				… >
	<Views:ViewBase.DataContext>
		<vms:HomeVM />
	</Views:ViewBase.DataContext>
</Views:ViewBase>

When the view is navigated to the OnNavigatedTo method is called. If this view has a constructed PageViewModel as the DataContext it is initialized here.

public class ViewBase : PhoneApplicationPage
{
	public PageViewModel PageViewModel { get { return DataContext as PageViewModel; } }

	protected override void OnNavigatedTo(NavigationEventArgs e)
	{
		if (PageViewModel != null)
		{
			var parameters = e.NavigationMode == NavigationMode.Back ? null : NavigationContext.QueryString;
			PageViewModel.Initialize(parameters);
		}
		base.OnNavigatedTo(e);
	}
}

Notice that the NavigationContext.QueryString is only passed into Initialize if this navigation is NavigationMode.New. This is important. When the user navigates forward in the app the NavigationMode will be New. In this case the NavigationContext.QueryString is required because the VM has never been initialized before and has no data. However, if the NavigationMode is Back then this VM has already been initialized with data so we only need to initialize the VM without data.

public abstract class PageViewModel : ViewModelBase
{
	public void Initialize(IDictionary<string, string> parameters = null)
	{
		InitilizeAlways();
		if (!IsInitialized)
		{
			bool isLaunching;
			CoreApplicationService.TryRetrieveTombstoningValue(
				CoreApplicationService.IS_LAUNCHING_KEY, out isLaunching);
			if (parameters != null &&
				(parameters.ContainsKey(CoreApplicationService.IS_RUNNING_KEY) || isLaunching))
			{
				InitializeFromNavigation(parameters);
			}
			else if (!HasState)
			{
				InitializeFromActivation();
			}
			HasState = true;
			IsInitialized = true;
		}
	}
	
	protected virtual void InitilizeAlways()
	{
		SubscribeGlobalHandlers();
	}

	protected virtual void InitializeFromNavigation(IDictionary<string, string> parameters) { }

	protected virtual void InitializeFromActivation() { }
	
	protected virtual void InitializeWithState() { }
	
	protected virtual void SubscribeGlobalHandlers()
	{
		if (!IsSubscribed)
		{
			CoreApplicationService.Deactivated += DeactivatedHandler;
			CoreApplicationService.Closing += ClosingHandler;
			IsSubscribed = true;
		}
	}
}

Inside of Initialize there are a few actions to perform. The first is to initialize anything that needs to always be initialized via the virtual method InitializeAlways. Generally nothing should be done here except hookup Global event handlers with the virtual method SubscribeGlobalHandlers. SubscribeGlobalHandlers is always called inside of InitializeAlways however, the code inside is only run if the property IsSubscribed is false. IsSubscribed is false if the VM has not been initialized or if it has been torn down.

After InitializeAlways a check is performed to know if the VM is Initialized or not. If it is not then execution continues. The next check is to discover if the VM is being initialized because it the app was launched or from some other action while the app was running. The launched indicator is set in the CAS when it is initialized. The first VM to be initialized is responsible for removing this key from the Tombstoning values.

public class CoreApplicationService
{
	public void Initialize(PhoneApplicationFrame frame, bool isLaunching)
	{
		…
		StoreTombstoningValue(IS_LAUNCHING_KEY, isLaunching);
	}
}

The is running key is set each time the CoreApplicationService.Navigate method is called. If the VM is being initialized from launching or running then the parameters dictionary is passed to the virtual method InitializeFromNavigation. This method would be overridden by VMs that need data from the parameters, which is the NavigationContext.QueryString dictionary. If this method was called a few things can be inferred. The first is that this is a new, or forward navigation and this VM has never been initialized before meaning it has no state.

If the VM is not initializing from launching or running then it is initializing from deactivation. When coming from deactivation there are two possibilities: State is preserved or state was disposed. The VM uses the HasState property to know if state exists. This property is set to true at the end of Initialize and is never set to false. The only time the property would be false is if the VM was newly constructed and not yet initialized. If HasState is true then the virtual method InitializeWithState is called. Here is where we would do very very minimal code to refresh data that could have changed since deactivation. Usually, no work should be done in this method unless absolutely necessary. Fast Application Switching relies on as little code being run as possible when state has been preserved. If HasState is false then the virtual method InitializeFromActivation is called. When this method is called we know that no state exists and we need to access Tombstoning values through the CAS.

Just before exiting Initialize the HasState and IsInitialized properties are both set to true. At this point the VM is initialized and ready to go. If data needs to be pulled from web servers or other long running tasks during initialization make sure that the work is done async and that a busy indicator and message is used in place of the missing data. This is better than showing a blank page because most users will think a blank page is a broken page. Also, please cache data when possible. No need to store the entire web on the phone, but don’t make the user wait to see data every time the app is loaded. This is a huge complaint of mine when I use apps that display RSS feeds and each time I load the app the entire feed must be pulled from the server before I can see the articles I was reading a few minutes prior.

Uninitialize

There are three different time when the VM should be uninitialized: Navigating forward to a new view or out of the app, navigating backward, and when the view is removed from the navigation back stack. The VM is notified about all three of these cases by the ViewBase class.

public class ViewBase : PhoneApplicationPage
{
	protected override void OnNavigatedFrom(NavigationEventArgs e)
	{
		if (PageViewModel != null)
		{
			PageViewModel.Uninitialize(e.NavigationMode == NavigationMode.Back);
		}
		base.OnNavigatedFrom(e);
	}
	
	protected override void OnRemovedFromJournal(JournalEntryRemovedEventArgs e)
	{
		if (PageViewModel != null)
		{
			PageViewModel.Uninitialize(true);
		}
		base.OnRemovedFromJournal(e);
	}
}

The OnNavigatedFrom method is used to indicate navigation forward or backward events from this view. If the navigation is a back navigation then indicate to Uninitialize that a tear down is requested. The OnRemovedFromJournal method indicates that the view has been removed from the back stack and will not be used again. Uninitialize is immediately called with the tear down flag.

A question to ask here is should the VM always be uninitialized when it’s not in use? Or should it just have a pause setting? In this approach uninitializing the VM is always desired when it is not in use, but tearing down the VM is not. Tear down means the VM will never be used again, essentially it’s the VM dispose method without actually using the dispose pattern.

public abstract class PageViewModel : ViewModelBase
{
	public void Uninitialize(bool isTearDown = false)
	{
		UninitializeAlways();
		if (isTearDown)
		{
			UninitializeTearDown();
		}
		IsInitialized = false;
	}
	
	protected virtual void UninitializeAlways() { }
	
	protected virtual void UninitializeTearDown()
	{
		UnsubscribeGlobalHandlers();
	}

	protected virtual void UnsubscribeGlobalHandlers()
	{
		if (IsSubscribed)
		{
			CoreApplicationService.Deactivated -= DeactivatedHandler;
			CoreApplicationService.Closing -= ClosingHandler;
			IsSubscribed = false;
		}
	}
}

Uninitialize first calls the UnitializeAlways virtual method. Work done in UninitializeAlways should be things like pausing media elements, timers, and web service queries. Also, unhooking any handlers that should not be handled while the view is not in use. It’s important to know that views that are in the back stack still run code. They are not dormant or prevented from executing code, therefore any handlers that could cause code to run should generally be disabled. A possible candidate to ignore this might be a live feed that is expected to continue updating even while not on that view. Performance and battery life and the two reasons for this rule.

After UninitializeAlways if the isTearDown argument is true then the UninitializeTearDown virtual method is called. This method should be used to clean up anything on the page that needs to be disposed of, closed, etc. UninitializeTearDown is responsible for calling the virtual method UnsubscribeGlobalHandlers which simply unsubscribes from events such as app deactivating, closing, and error notifications. Nice and straight forward.

At the end of Uninitialize the property IsInitialized is set to false. There is no need to if the VM was torn down or not because a torn down VM will never be used again.

Integrating with the CoreApplicationService

The CAS is available as a singleton anywhere in the app, but we have found it nice to have a simple property in the VM to call. This also aids in replacing the CAS if needed with something else. As you saw above in the SubscribeGlobalHandlers method the VM subscribes to the Closing and Deactivated events on the CAS. These events are also not unsubscribed to unless the VM is being torn down. When either of these events are raised by the app the CAS receives then and passes them on to whom ever desires them, in this case the VM cares. The PageViewModel then calls a virtual method related to the event that was raised. If the Closing event is raised the PageViewModel calls the related virtual method Close. If the Deactivated event is raised the PageViewModel calls the virtual method Deactivate. This just aids in exposing methods and events that should be used in almost every VM that inherits from PageViewModel. The argument was proposed to make the methods abstract forcing derived types to implement the methods, but was eventually lost to keep them virtual and hope the developer is responsible and thinks through the flow of data and the app.

public abstract class PageViewModel : ViewModelBase
{
	protected CoreApplicationService CoreApplicationService
	{
		[DebuggerStepThrough]
		get { return CoreApplicationService.Instance; }
	}
	
	protected virtual void Deactivate()
	{
	}
	
	private void DeactivatedHandler(object sender, EventArgs e)
	{
		Deactivate();
	}
	
	protected virtual void Close()
	{
	}
	
	private void ClosingHandler(object sender, EventArgs e)
	{
		Close();
	}
}

The Close method is called when the user uses the back button of the phone to leave the app. In this method all data that needs to be persisted for future runs of the application need to be saved. Data that is transient like form data can be ignored.

The Deactivated method is called when the user hits the Windows logo button, or touches a notification that opens another app such as an SMS notification opens the Messaging app. This happens a lot more often than Close and needs special attention in each VM that is in the back stack or in use when called. In this method all persistent data needs to be saved in persistent storage and all transient data such as form data needs to be stored in transient storage. More information about the difference between persistent and transient storage and what data goes where read my post Windows Phone 7 – Tombstoning. Use the CAS to store transient data with the StoreTombstoningValue method.

public class CoreApplicationService
{
	public void StoreTombstoningValue(string key, object value)
	{
		PhoneApplicationService.Current.State[key] = value;
	}
}

In my experience with apps in the market place this is one area where most of them are only OK. I could spend hours discussing proper ways to handle app lifecycle and data flow, but I will spare you in this post.

Conclusion

Armed with everything you’ve learned here and in previous posts about the CAS you’re ready to start your very own MVVM Windows Phone application. App ideas, of course, must be supplied by your own creative juices, but there’s no shame in copying an idea for the purposes of learning. This post also brings us one post closer to having complete coverage of the Framework Components introduced in LionHeart.

Code Camp: Windows Phone 7.5 Simplified

First off thank you to everyone who attended my session at code camp. I hope you learned something new! I’d love to get feedback on how you felt the presentation went. Please leave me some comments here or shoot me an email or whatever.

In this session I used an app codenamed LionHeart to help explain the concepts and framework I presented. To learn more about the framework I have a blog series named Simplifying the Windows Phone Development Experience! Codename: LionHeart. In this series I go in much more depth about the same concepts I presented on.

Please note the source code release does not have fully completed app however, the framework used in the app is stable and the API’s are almost locked down.

When the framework is complete it will be available in Project Template form. This will allow you to easily start a new Windows Phone project with all of the boring boiler plate work completed for you.

Presentation Slide Deck

Source Code: LionHeart (codecamp release)

Cheers! And Happy Coding!

WP7 Simplified: CoreApplicationService (Tombstoning)

This post brings closure to coverage of the CoreApplicationService (CAS) in this series titled WP7 Simplified. The final topic to cover is how the CAS handles tombstoning. Before getting into that let’s discuss what tombstoning is first. There are a couple of different terms to be familiar with that all refer to the tombstoning process: App Deactivation, Fast Application Switching, Tombstoning.

App Deactivation

When ever a user navigates leaving the app, except when they use the back button to close the app, the app is deactivated. All of the application state is stored in memory and app execution has 10 seconds to pause (Read the very last caution in the documentation). During deactivation it is important to store any transient and persistent state/data. From this state the application can be activated without losing any state in which case little if any state needs to be restored because the OS didn’t dispose of any part of the app state. The app could also be tombstoned which means that all state will need to be restored, but the application can still be activated. Finally the app might be completely closed by the OS thus requiring a fresh start.

Fast Application Switching

When an app is activating and the OS preserved state, the app should not attempt to do a full state restore, but instead should leverage the fact that the OS preserved the app’s previous state.

Tombstoning

If an app is tombstoned it means that all app state has been removed from the OS memory. This is why it is important for developers to store app state in transient or persistent data stores during app deactivation. When an app is activated from being tombstoned it should appear in the exact same state it was in before the user deactivated the app. It should also look the same as if the app had utilized Fast Application Switching.

For a much better explanation of these topics and some coverage of the difference between what persistent and transient data stores are available in Windows Phone please read my post Windows Phone 7 – Tombstoning.

Handling Tombstoning in CoreApplicationService

In the CAS only transient data is handled. We use DataProviders for persistent data. When deciding what transient data needs to be stored for tombstoning remember that we need to be able to restore the app during activation to the exact same state it was left in. Think of Leave No Trace from Boy Scouts and camping, we don’t want to leave any trace that the app was ever deactivated or tombstoned. Also, keep in mind when storing full objects that the object reference after retrieving a tombstoned value will be different than the object reference that was stored. If the reference needs to be the same the object should be stored in a persistent data store that should hand out the same reference for that object each time it is requested. We store values for tombstoning with the CAS using the following API.

public void StoreTombstoningValue(string key, object value)
{
	PhoneApplicationService.Current.State[key] = value;
}

public bool TryRetrieveTombstoningValue<T>(string key, out T value, bool clearKey = false)
{
	object tempObj;
	var exists = PhoneApplicationService.Current.State.TryGetValue(key, out tempObj) && tempObj is T;
	value = exists ? (T)tempObj : default(T);

	if (clearKey)
	{
		ClearTombstoningValue(key);
	}

	return exists;
}

public void RemoveTombstoningValue(string key)
{
	PhoneApplicationService.Current.State.Remove(key);
}

Store Tombstoning Value

Windows Phone provides developers with the PhoneApplication.Current.State dictionary which will survive as long as the app is not closed. Here is where we store all transient data.

Try Retrieve Tombstoning Value<T>

When retrieving a value we wanted to streamline the experience. Thus, this method is generic and does all the checks and casts each time a value is requested. It reports weather the value was found and cast correctly. It optionally takes in a parameter indicating to clear the value out of the State dictionary.

Remove Tombstoning Value

After retrieving a tombstoning value for the last time it should be removed to decrease memory usage.

Quick Tip of What to Store for Tombstoning

As much as possible only store object Id’s instead of the full objects. Even if at the moment the reference to that object doesn’t matter it may matter down the road. The naming of these methods is also very important. It is strongly suggested to not use the State dictionary to store objects during navigation. While it is true that a full object can be stored in the State dictionary before navigation for the next page to access after navigation, the object references are different because the State dictionary serializes and then deserializes all objects being stored then retrieved. This fact hurt one of our last projects. Once we had a grip on this principle we were OK, but until then bug after bug would manifest and they were difficult to track down.

Conclusion

Nothing super fancy this time. The motivation to include this functionality in the CAS was the constant repetition of the code in TryRetrieveTombstoningValue<T>(). It has helped clean up our code base quite a bit. This post also concludes code coverage of the CAS. The CAS is a very key component to any Windows Phone development. We’re excited to hear how you use it or how the principles discussed around it have helped you. Leave some comments to let us know. Next in the series we will be covering PageViewModel which works closely with ViewBase which we discussed in the previous post of this series WP7 Simplified: CoreApplicationService (Navigation).

WP7 Simplified: CoreApplicationService (Navigation)

My last post in this series covered the CoreApplicationService (CAS) and how it handles app lifecycle which is part of a broad series discussing how to simplify Windows Phone development. In the lifecycle post navigation was discussed only lightly. This post aims to cover the CAS and how it handles navigation. It will also, cover a few open questions about lifecycle from my previous post. The CAS was originally created and used for navigation exclusively. Desires for centralized lifecycle, tombstoning, and navigation management drove us to buff out the former NavigationService and rename it as CoreApplicationService. Since the NavigationService, we have optimized, simplified, and fundamentally improved navigation on Windows Phone applications.

Lesson #1: Centralize Data

The most important of lessons that we learned was to make sure data is centralized in the app. Any object reference that needs to be passed to the next page can only do so if the reference to that object is available from a centralized data provider. We won’t cover data providers here, but I wanted to bring this lesson to the forefront in order to help bring clarity to the thought process behind the navigation paradigm used in the CAS. We had unknowingly painted ourselves into a corner during our development one of the phone apps we developed. We desired to modify the same object reference in two related pages. We made the mistake of storing the object in the PhoneApplicationService.Current.State dictionary. What we didn’t realized until the final weeks of development and testing was that State dictionary serializes the objects stored in it. That means when obtaining an object stored in the State dictionary it was being deserialized as a new object. We would then modify that object and return back to the first page. The first page would then assume the object was updated when in reality a different object reference had been used and updated. This was a huge bummer to realize so late and taught us to never pass objects via the State dictionary if we need the original object reference.

With that said lets get into some navigation topics.

Navigation Infrastructure

Those familiar with Windows Phone development know that in order to perform any kind of navigation you must use the PhoneApplicationFrame. When initializing the CAS in App.xaml we pass in the PhoneApplicationFrame. This gives us the ability to navigate without requiring a PhoneApplicationPage which is the built in intermediary to the PhoneApplicationFrame. The navigation framework in the CAS is essentially a more developer friendly API wrapper for the PhoneApplicationFrame navigation framework. Our goal was to expose all of the PhoneApplicationFrame navigation framework while buffing out the points where it was lacking.

public class CoreApplicationService
{
	private PhoneApplicationFrame _frame;

	public event EventHandler<NavigatingCancelEventArgs> Navigating;
	private void OnNavigating(NavigatingCancelEventArgs e)
	{
		var handler = Navigating;
		if (handler != null) handler(this, e);
	}

	public event EventHandler<NavigationEventArgs> Navigated;
	private void OnNavigated(NavigationEventArgs e)
	{
		var handler = Navigated;
		if (handler != null) handler(this, e);
	}

	public Dictionary<object, string> Mappings { get; private set; }

	public void Initialize(PhoneApplicationFrame frame, bool isLaunching)
	{
		LittleWatson.CheckForPreviousException();
		_frame = frame;
		_frame.Navigated += FrameNavigatedHandler;
		_frame.Navigating += FrameNavigatingHandler;
		PersistTombstoningValue(IS_LAUNCHING_KEY, isLaunching);
	}
	
	private void FrameNavigatedHandler(object sender, NavigationEventArgs e)
	{
		OnNavigated(e);
	}

	private void FrameNavigatingHandler(object sender, NavigatingCancelEventArgs e)
	{
		OnNavigating(e);
	}
}

Navigation Mappings

This is one are of functionality where we’re trying to optimize still. Currently we have a dictionary of object to string mappings. The string represents the Uri to a page while the object is some arbitrary key that maps to that page. Managing the keys is the difficult part that we haven’t quite figured out yet. Here is how we register the mappings in LionHeart.

public partial class App : Application
{
	private void InitializeNavigationMappings()
	{
		CoreApplicationService.Instance.Mappings.Add(ViewKeys.HOME_VIEW_KEY, "/Views/HomeView.xaml");
		CoreApplicationService.Instance.Mappings.Add(ViewKeys.MY_VIEW_KEY, "/Views/MyView.xaml");
		CoreApplicationService.Instance.Mappings.Add(ViewKeys.ALL_CLIENTS_VIEW_KEY, "/Views/AllClientsView.xaml");
		CoreApplicationService.Instance.Mappings.Add(ViewKeys.CLIENT_VIEW_KEY, "/Views/ClientView.xaml");
		CoreApplicationService.Instance.Mappings.Add(ViewKeys.MY_REPORTS_VIEW_KEY, "/Views/MyReportsView.xaml");
		CoreApplicationService.Instance.Mappings.Add(ViewKeys.REPORT_VIEW_KEY, "/Views/ReportView.xaml");
		CoreApplicationService.Instance.Mappings.Add(ViewKeys.ALL_SESSIONS_VIEW_KEY, "/Views/AllSessionsView.xaml");
		CoreApplicationService.Instance.Mappings.Add(ViewKeys.MY_SESSIONS_VIEW_KEY, "/Views/MySessionsView.xaml");
		CoreApplicationService.Instance.Mappings.Add(ViewKeys.SESSION_VIEW_KEY, "/Views/SessionView.xaml");
		CoreApplicationService.Instance.Mappings.Add(ViewKeys.SETTINGS_VIEW_KEY, "/Views/SettingsView.xaml");
	}
}

By using this dictionary of mappings we gain a huge amount of flexibility. This allows the developer to expose and manage navigation keys in lower tiers of the app if desired. In the sample code we use a struct named ViewKeys to manage or contain all view keys. We’ve tried using object types as the key, but we always seemed to come to a point where we were mixing types into ViewModels that shouldn’t know about certain types and tightly coupling types to views. That doesn’t sound all bad, but from experience a struct of string keys has been one of the cleanest and readable approaches.

Note on Managing Views and ViewModels in the CAS: The PhoneApplicationFrame has a BackStack property that manages all pages that are alive in the app. We didn’t want to manage Views or ViewModels in the CAS because that work was already being done by the PhoneApplicationFrame. We also didn’t want to tightly couple the CAS the UI tier, in fact that’s exactly why we need the CAS is that the PhoneApplicationFrame is only available in the UI tier unless passed into a different tier. The CAS is immediately available to ViewModels and any other tier above the very base tier.

Here’s a look at ViewKeys:

public struct ViewKeys
{
	public static readonly string HOME_VIEW_KEY = "HOME_VIEW_KEY";
	public static readonly string MY_VIEW_KEY = "MY_VIEW_KEY";
	public static readonly string ALL_CLIENTS_VIEW_KEY = "ALL_CLIENTS_VIEW_KEY";
	public static readonly string CLIENT_VIEW_KEY = "CLIENT_VIEW_KEY";
	public static readonly string MY_REPORTS_VIEW_KEY = "MY_REPORTS_VIEW_KEY";
	public static readonly string REPORT_VIEW_KEY = "REPORT_VIEW_KEY";
	public static readonly string ALL_SESSIONS_VIEW_KEY = "ALL_SESSIONS_VIEW_KEY";
	public static readonly string MY_SESSIONS_VIEW_KEY = "MY_SESSIONS_VIEW_KEY";
	public static readonly string SESSION_VIEW_KEY = "SESSION_VIEW_KEY";
	public static readonly string SETTINGS_VIEW_KEY = "SETTINGS_VIEW_KEY";
}

Not very exciting… And moving on.

Performing Navigation

Now we get into the exciting stuff. How we perform a navigation. Here is some code from LionHeart in HomeVM and helper class NavigationDefinition to help illustrate how to do this.

<ListBox x:Name="Menu"
	ItemsSource="{Binding NavigationOptions}"
	SelectedItem="{Binding NavigationTarget, Mode=TwoWay}"
	DisplayMemberPath="Name"
	toolkit:TiltEffect.IsTiltEnabled="True"/>

public class HomeVM : PageViewModel
{
	private List<NavigationDefinition> _navigationOptions;
	public List<NavigationDefinition> NavigationOptions
	{
		[DebuggerStepThrough]
		get { return _navigationOptions; }
		set
		{
			if (value != _navigationOptions)
			{
				_navigationOptions = value;
				OnPropertyChanged("NavigationOptions");
			}
		}
	}
	
	private NavigationDefinition _navigationTarget;
	public NavigationDefinition NavigationTarget
	{
		[DebuggerStepThrough]
		get { return _navigationTarget; }
		set
		{
			if (value != _navigationTarget)
			{
				_navigationTarget = value;
				OnPropertyChanged("NavigationTarget");
				Navigate(_navigationTarget);
			}
		}
	}
	
	private void InitializeMenu()
	{
		if (NavigationOptions == null)
		{
			NavigationOptions = new List<NavigationDefinition>(new[]
				{
					new NavigationDefinition(MY_SESSIONS_MENU_ITEM_NAME,
						ViewKeys.MY_VIEW_KEY,
						new Dictionary<string,string>{{NavigationKeys.PIVOT_ITEM_KEY, MyPivotItem.Sessions.ToString()}}),
					new NavigationDefinition(MY_CLIENTS_MENU_ITEM_NAME,
						ViewKeys.MY_VIEW_KEY,
						new Dictionary<string,string>{{NavigationKeys.PIVOT_ITEM_KEY, MyPivotItem.Clients.ToString()}}),
					new NavigationDefinition(MY_REPORTS_MENU_ITEM_NAME,
						ViewKeys.MY_VIEW_KEY,
						new Dictionary<string,string>{{NavigationKeys.PIVOT_ITEM_KEY, MyPivotItem.Reports.ToString()}}),
					new NavigationDefinition(CREATE_REPORT_MENU_ITEM_NAME,
						ViewKeys.REPORT_VIEW_KEY),
					new NavigationDefinition(SETTINGS_MENU_ITEM_NAME,
						ViewKeys.SETTINGS_VIEW_KEY),
				});
		}
	}
	
	private void Navigate(NavigationDefinition definition)
	{
		if (definition != null)
		{
			NavigationTarget = null; // reset selection
			CoreApplicationService.Navigate(definition.Key, definition.Parameters);
		}
	}
}

public class NavigationDefinition
{
	public NavigationDefinition(string name, object key, Dictionary<string, string> parameters = null)
	{
		Name = name;
		Key = key;
		Parameters = parameters;
	}
	
	public string Name { get; private set; }
	public object Key { get; private set; }
	public Dictionary<string, string> Parameters { get; private set; }

}

NavigationDefinition

This simple helper class is just a wrapper for the desired ViewKey, a dictionary of parameter keys and values, and a display friendly name. This class helps to with creating a menu of navigation options in the UI such as the one created in HomeVM.InitializeMenu() in the sample code above.

When we navigate we can append parameters to the page Uri when we pass it to the PhoneApplicationFrame. In HomeVM.InitializeMenu() we create parameters for each NavigationDefinition with a key of ViewKeys.MY_VIEW_KEY. In this case the parameters will be used to determine which pivot item is in view when the user navigates to MyView. How this is done will be covered in a future post.

In HomeView there is a ListBox which displays each NavigationDefinition. The selection of the ListBox is bound to HomeVM.NavigationTarget. When the user selects a definition and NavigationTarget is set we call Navigate() from it’s setter. Navigate() in turn calls CoreApplicationService.Navigate() passing it the view key and the dictionary of parameters.

Processing a Navigation Request

public class CoreApplicationService
{
	/// <summary>
	/// Navigates the specified viewKey.
	/// </summary>
	/// <param name="viewKey">The viewKey.</param>
	/// <param name="parameters">The parameters.</param>
	/// <param name="countToRemoveFromBackStackAfterNavigation">The count to remove from back stack. (ignored if clearBackStack == <c>true</c>)</param>
	/// <param name="clearBackStack">if set to <c>true</c> [clear back stack].</param>
	public void Navigate(object viewKey, Dictionary<string, string> parameters = null, 
		int countToRemoveFromBackStackAfterNavigation = 0, bool clearBackStack = false)
	{
		string target;
		if (viewKey != null && Mappings.TryGetValue(viewKey, out target))
		{
			parameters = parameters ?? new Dictionary<string, string>();
			parameters.Add(IS_RUNNING_KEY, true.ToString());
	
			ICollection<string> parameterKeyValueStrings =
				parameters.Keys.Select(key => string.Format("{0}={1}", key, parameters[key])).ToArray();
	
			target += string.Format("?{0}", string.Join("&", parameterKeyValueStrings));
	
			if (clearBackStack)
			{
				_frame.Navigated += NavigationReadyToClearBackStackHandler;
			}
			else if (countToRemoveFromBackStackAfterNavigation > 0)
			{
				_countToRemoveFromBackStackAfterNavigation = countToRemoveFromBackStackAfterNavigation;
				_frame.Navigated += NavigationReadyToRemoveCountFromBackStack;
			}
	
			_frame.Navigate(new Uri(target, UriKind.RelativeOrAbsolute));
		}
		else
		{
			throw new ArgumentException(string.Format("Cannot navigate to target view. Driver={0}", viewKey));
		}
	}
}

Here we find the meat of navigation processing. The first thing done here is a check to validate the viewKey is a valid key to a page Uri then acquires the target page Uri. If no parameters were passed an empty parameters dictionary is created and immediately we add a parameter for IS_RUNNING_KEY which is always set to true if this method is called. The IS_RUNNING_KEY key is used by ViewModels in order to know how to initialize. Again, another topic that will be covered in a future blog post. After the parameters collection is finalized the CAS then appends each parameter to the target Uri forming the finalized target Uri.

The next step is to hook up handlers for the PhoneApplicationFrame.Navigated event when necessary. Sometimes it is desirable to perform a navigation that clears the entire PhoneApplicationFrame.BackStack. Other times, it is desirable to remove a specified number of pages from the PhoneApplicationFrame.BackStack. If clearBackStack is true then after navigation is complete the CAS clears the PhoneApplicationFrame.BackStack. If clearBackStack is false and countToRemoveFromBackStackAfterNavigation is greater than 0 then after navigation completes the CAS removes the specified number of page entries from the PhoneApplicationFrame.BackStack. This functionality is helpful for navigating to menu pages and in app navigation resets.

Finally, the CAS calls PhoneApplicationFrame.Navigate() allowing Windows Phone to take over.

ViewBase and Handling Navigation in Pages

First, there is currently a disconnect in terminology. Windows Phone calls each View a Page, and here at Interknowlogy we’re in the habit of calling each Page a View. So each term means exactly the same thing and we’re working on simplifying our terminology. With that aside lets look at ViewBase.

ViewBase becomes the new base class of each View in the app. This cuts down on duplicating this code for each view. Because of that maintainability goes up, which is always a good thing.

public partial class HomeView : ViewBase
{
	public HomeView()
	{
		InitializeComponent();
	}
}

public class ViewBase : PhoneApplicationPage
{
	public PageViewModel PageViewModel { get { return DataContext as PageViewModel; } }

	protected override void OnNavigatedTo(NavigationEventArgs e)
	{
		if (PageViewModel != null)
		{
			PageViewModel.Initialize(NavigationContext.QueryString);
		}
		base.OnNavigatedTo(e);
	}

	protected override void OnNavigatedFrom(NavigationEventArgs e)
	{
		if (PageViewModel != null)
		{
			PageViewModel.Uninitialize(e.NavigationMode == NavigationMode.Back);
		}
		base.OnNavigatedFrom(e);
	}

	protected override void OnRemovedFromJournal(JournalEntryRemovedEventArgs e)
	{
		if (PageViewModel != null)
		{
			PageViewModel.Uninitialize(true);
		}
		base.OnRemovedFromJournal(e);
	}
}

ViewBase is by no means required, but it is a nice piece of reusable code. Each page desiring to leverage the navigation framework must have a ViewModel derived from PageViewModel as its DataContext. ViewBase is responsible for knowing what to do with its ViewModel and when to do it. It knows that in OnNavigatedTo the ViewModel needs to be Initialized with the specified parameters, and that in OnNavigatedFrom and OnRemovedFromJournal the ViewModel needs to be Uninitialized and how. OnRemovedFromJournal is called on a Page when it is removed from the PhoneApplicationFrame.BackStack.

Conclusion

The CAS makes navigation more powerful and flexible. It’s simple to request navigation via the CAS and it’s reliable. The CAS does not replace existing navigation options, instead it builds upon the existing framework and extends possibilities. The CAS also makes navigation more reusable and readable inside ViewModels. I hope this post helps inspire innovation with Windows Phone.

WP7 Simplified: CoreApplicationService (Lifecycle)

In my post Simplyfying the Windows Phone Development Experience! Codename: LionHeart I explain that LionHeart is a demo app that I’m using to prove out a few lessons we’ve learned here at IK from our last Windows Phone project. In this post I will start to get into the meat of the app starting in a class named CoreApplicationService (CAS).

What is CoreApplicationService’s Purpose?

Event Forwarding

One of the purposes of the CoreApplicationService (CAS) is to expose events from across the app to ViewModels (VMs) or any other class that is not instantiated by App.xaml. This class acts, in a very simplified way, as an event aggregator. It is not, however, an event aggregator as found in Prism. Instead it’s more of a one to one event forwarding class. For example, in App.xaml there are two events named Deactivated and Closing. Therefore, in the CAS there are two identical events named Deactivated and Closing. When the event is handled in App.xaml.cs we simply forward the handling onto the CAS as show in this example:

public partial class App : Application
{
   private void ApplicationDeactivated(object sender, DeactivatedEventArgs e)
   {
       CoreApplicationService.Instance.OnDeactivated(e);
   }
}

Currently the events handled in the CAS are:

From App.xaml

  • Deactivated
  • Closing
  • Obscured
  • Unobscured
  • NavigationFailed
  • UnhandledException

From PhoneApplicationFrame

  • Navigating
  • Navigated

In all cases, the CAS acts as a forwarding system for any object the desires to subscribe to these events. In LionHeart those objects are usually VMs. This pattern allows the VM to be responsible for knowing when and what to do during these events. This pattern has made more and more sense as we’ve discussed possible solutions to our problem of telling VMs when to Deactivate (prepare for tombstoning) etc.

Error Reporting

Another responsibility of CAS is to prompt the consumer of the app to send error data to the developer. We found Little Watson created by Andy Pennell at Microsoft which simply collects unhandled exception information and stores it in a file in IsolatedStorage before the app closes. The next time the consumer launches the app they are prompted to send the error file to the developer, which they can choose to not send it if they desire. The error file is then deleted and the application will not prompt again until an error file exists again. This is so helpful I cannot even begin to express how many bugs we have been able to track down because of this tool. I want to start buffing this helper class out with logging since the error information we receive on the phone is not as helpful as it could be. Adding a logging feature that began each time the application was launched would be of even greater benefit.

Navigation

This purpose is what originally drove us to create the CAS. In fact we had originally named the CAS as NavigationService, but as it’s functionality increased and purpose morphed we decided that name was to specific and did not convey what we wanted. Navigation will be covered in greater detail in another post. In simple terms we use a dictionary of object to string mappings. Each string represents the Uri to a page. These mappings are set immediately after initializing the CAS as shown in the section below “How to use CoreApplicationService.”

public partial class App : Application
{
   private void InitializeNavigationMappings()
   {
       CoreApplicationService.Instance.Mappings.Add(ViewKeys.HOME_VIEW_KEY, "/Views/HomeView.xaml");
       CoreApplicationService.Instance.Mappings.Add(ViewKeys.MY_VIEW_KEY, "/Views/MyView.xaml");
       CoreApplicationService.Instance.Mappings.Add(ViewKeys.ALL_CLIENTS_VIEW_KEY, "/Views/AllClientsView.xaml");
       CoreApplicationService.Instance.Mappings.Add(ViewKeys.CLIENT_VIEW_KEY, "/Views/ClientView.xaml");
       CoreApplicationService.Instance.Mappings.Add(ViewKeys.MY_REPORTS_VIEW_KEY, "/Views/MyReportsView.xaml");
       CoreApplicationService.Instance.Mappings.Add(ViewKeys.REPORT_VIEW_KEY, "/Views/ReportView.xaml");
       CoreApplicationService.Instance.Mappings.Add(ViewKeys.ALL_SESSIONS_VIEW_KEY, "/Views/AllSessionsView.xaml");
       CoreApplicationService.Instance.Mappings.Add(ViewKeys.MY_SESSIONS_VIEW_KEY, "/Views/MySessionsView.xaml");
       CoreApplicationService.Instance.Mappings.Add(ViewKeys.SESSION_VIEW_KEY, "/Views/SessionView.xaml");
       CoreApplicationService.Instance.Mappings.Add(ViewKeys.SETTINGS_VIEW_KEY, "/Views/SettingsView.xaml");
   }
}

In the example code above you will notice the use of ViewKeys which is a struct that contains string values that we use as keys. The key does not need to be a string instead it can be any object. Sometimes we will use typeof(object) for views that represent specific types. We found that strings were required for some views and decided to go with all strings for consistency. Remembering that VMs will be requesting navigation most of the time we did not use typeof(Page) as the key, because VMs should not have access to those types.

How to use CoreApplicationService

The CAS is provided via a static property of itself named Instance as a singleton. There are two times the CAS will need to be instantiated. The first is when the application is Launching. The second case is when the application is being Activated, but only if there is no application state. In both cases no VMs exist yet, therefore the CAS will not forward the Launching and Activating events because no object would or could receive them. Instead we use the events to initialize the CAS.

public class CoreApplicationService
{
   private static CoreApplicationService _instance;
   public static CoreApplicationService Instance
   {
       get { return _instance ?? (_instance = new CoreApplicationService()); }
   }
}

public partial class App : Application
{
   private void Initialize(bool isLaunching)
   {
       CoreApplicationService.Instance.Initialize(RootFrame, isLaunching);
       InitializeNavigationMappings(); //As shown in above section “What is CoreApplicationService’s Purpose?” and subsection “Navigation”.
   }

   private void ApplicationLaunching(object sender, LaunchingEventArgs e)
   {
       Initialize(true);
   }

   private void ApplicationActivated(object sender, ActivatedEventArgs e)
   {
       if (!e.IsApplicationInstancePreserved)
       {
           Initialize(false);
       }
   }
}

Initialize accepts two parameters: the PhoneApplicationFrame which is used for navigation, and a boolean indicating if the application is launching.

public class CoreApplicationService
{
   public void Initialize(PhoneApplicationFrame frame, bool isLaunching)
   {
       LittleWatson.CheckForPreviousException();

       _frame = frame;
       _frame.Navigated += FrameNavigatedHandler;
       _frame.Navigating += FrameNavigatingHandler;

       PersistTombstoningValue(IS_LAUNCHING_KEY, isLaunching);
   }
}

The reason for the boolean is for VM initialization. This will be explained in much greater detail later on, but for those curious minds out there during Activating (without state) when VMs initialize there are no navigation parameters. This is used as an indication that the application was tombstoned. Because this same state exists during Launching we must differentiate the two somehow. We got around this by adding a boolean to the tombstoning values that is checked for when no navigation parameters exist and indicates the application is Launching not Activating. As I stated before I will cover this in later posts in greater detail.

Conclusion

This concludes the introduction into the CoreApplicationService and how it plays into the lifecycle of the phone app. This service is the backbone to LionHeart and all phone apps that use it. As we cover navigation and how VMs integrate with this service you’ll understand why it is so important and why it is so helpful. As always if you have any suggestions for improvement, comments, or questions please post them. This is not meant to be a one man show, but rather a starting point for phone app architecture.

WP7 Simplified: Wireframes and Information Map

UPDATE 7/12: This post is part of a broad series helping to simplify the development experience of Windows Phone apps. The beginning of the series can be found here.

In architecture a blueprint must exist before a house or office complex can be built. Without the blueprint there would be mass confusion and little if anything would ever happen. The final product would be disaster. The same concept applies to software especially on the phone. If you just start coding the resulting app would struggle to be coherent or usable to the consumer. In order to prevent this we need some kind of software blueprint to help the developer stay focused and deliver what is desired and intended. Over the last 3 years here at InterKnowlogy I’ve come across a variety of ways to represent the flow and design of an application. I have gone from paper to whiteboards to Visio to combinations of all of the above and more. What I’ve discovered is the digital formats take too long to accomplish anything so they are more of a final design asset rather than the means to get to the desired result. Whiteboards are my preferred medium for sketching wireframes and information flow. Microsoft has one of the coolest examples of wireframes participating in the flow of information called an Information Map. The example image on the aforementioned site is not the highest quality, but it demonstrates the intended purpose.

Information Map

As I mentioned earlier I don’t like going to a digital medium because I feel it takes too long to make it worth while. But I am a huge fan of the whiteboard so I’m including am image of the information map of LionHeart that I created on a whiteboard. Thus, digitizing my whiteboard information map. It’s not beautiful but it conveys the idea clear enough that I feel little to no need to rework it using Visio or some other pretty digital designer.

There are just a few important items to mention here. First, the Windows Phone platform has some strict navigation rules namely the back button always goes back to the previous page. There are times this rule can be ignored such as when going to a settings screen and selecting save. Hitting the back button after selecting save should not return to the settings screen in most cases. Essentially any screen that is treated more like a modal dialog should not be returned to via the back button. These cases should be called out in the information map. Second, certain UI aspects should be called out such as multi-select lists, pivot or panorama control, or other controls using none intuitive interactions (based on a static drawing). Finally, remember that these information maps only take the UI aspect of the application into account. Do show the layout to some of your colleges or potential consumers and make sure the flow of the app cuts down on as many touches as possible to accomplish what is important. Once the information map is complete then it’s time to move on to the project structure and start coding!

Code Architecture

This is an entire different beast. I will not be covering this topic now. Perhaps at a future time. Admittedly, code architecture is one of those religious wars that I absolutely LOVE to discuss. For now I will only say that after you have an information map completed decide on what models exist and what VMs exist. Remember if commands will be used for buttons such as with the BindableApplicationBar that VMs should be used. Also, take into account if you will be using IsolatedStorage or the local application database. LionHeart is designed around IsolatedStorage for purpose of its demo.

Simplifying the Windows Phone development experience! Codename: LionHeart

Each time you start a new project one of the first things most of us developers do is pull in code we want to reuse. If we don’t have any existing code then we try to figure out how to leverage concepts and theories from past experiences and platforms. The latter is exactly what we did during the development of my last project, a Windows Phone project. We have a ton of XAML and MVVM experience here at Interknowlogy, and a few of us had done small RECESS phone apps. None of us had done a full blown app from scratch on the phone before, but today I can say we did an awesome job! What I want to focus on are the lessons we learned from that project and how to apply them to future phone projects to help simplify the process. My coworker Tim Askins and I spent a few RECESS discussing what we could improve on and and what we thought went well. The result is what I call LionHeart.

Introduction to LionHeart

LionHeart is a demo phone app that I am working on that is applying the code lessons learned. These lessons include application lifecycle, navigation, tombstoning, MVVM on the phone, how to provide mock data vs. real data, styling, and many more. The project it self is a demo based on work my wife does as a Behavior Interventionist (BI) for children with autism. We got talking about what could potentially simplify her line of work as well as provide a compelling demo app for the phone. The resulting app will allow for BIs to create reports that are currently done on paper, then transferred to another paper and placed in a binder, then that binder is driven to the main office once a month, and then driven back to the client’s home where BIs go when then work with the children. Wow, that was a mouth full. The app will also allow BIs to view their schedule of sessions for the day/week/month/etc. from within the application. The schedule will also be integrated into the normal phone calendar from Windows Live as well. Individual client information will also be available including previous reports, charts showing progress, and whether there will be a supervisor attending the session as well. Sound like a full blown app? I’m really excited to bring this app to life. I just wish it wasn’t just a demo app.

Components of LionHeart

Let’s remind ourselves again that the reason we are am creating LionHeart is to help solidify patterns and practices on the phone that will help simplify and speed up the development process of future phone apps. Since there are so many components to LionHeart I wanted to give a brief overview of what I think some of those components will be over the next few weeks.

Framework Components

Application Components

  • HomeVM
  • Navigating to Pages with a Pivot Control and to a Specific PivotItem
  • Calendar Integration
  • Styling

With that said as I complete each post I’ll update the list with links.

Final Thoughts

When all is said and done these components should provide a solid foundation for developing on the Windows Phone platform. If you have any questions or thoughts about how to improve on our design please let me know. Happy Coding!

Bindable Application Bar (Attached Property) – Windows Phone 7

In a prior blog post I had created a Blend Behavior for creating a bindable ApplicationBar. The problem with the Blend Behavior is it seems to have a static instance that then attaches to multiple objects. It’s very confusing to me and I need to do a lot more research on Blend Behaviors. The result has been the creation of a BindableApplicationBar attached property.

I was able to repurpose the code I had written for the Blend Behavior. The new attached property is very simple. It has a collection of ApplicationBarIconButtonDelegate objects and a collection of ApplicationBarMenuItemDelegate objects. Long names I know, I’ll work on shortening those up. As soon as the BindableApplicationBar’s DataContext is set each button delegate’s and menu item delegate’s DataContext is set as well. At this point bindings kick in and based on visibility the BindableApplicationBar adds the delegates’ ApplicationBarIconButton or ApplicationBarMenuItem objects to the correct collections on the actual ApplicationBar. Confused? Let’s show some code.

Hooking up the attached property looks like this:

<Code:BindableApplicationBar.BindableApplicationBar>
	<Code:BindableApplicationBar>
		<!--NOTE: The ability to add more than 4 buttons and change their state based on binding. 
				If they are visible then they are added to the app bar, otherwise they are removed from the app bar.
			IMPORTANT: Always change the visibilty of the buttons in the app bar before those not in the app bar
				and avoid having 2 buttons bound to the same property for visibility-->
		<Code:BindableApplicationBar.ButtonDelegates>
			<Code:ApplicationBarIconButtonDelegate IconUri="/Images/appbar_button1.png"
													Text="{Binding TextCommandHeader}"
													Command="{Binding ChangeTextCommand}" />
			<Code:ApplicationBarIconButtonDelegate Text="Increase"
													Command="{Binding ChangeNumberCommand}" />
			<Code:ApplicationBarIconButtonDelegate Text="Toggle"
													IsVisible="{Binding CanToggleCanChangeNumber}"
													Command="{Binding ToggleCanChangeNumberCommand}" />
			<Code:ApplicationBarIconButtonDelegate Text="Hide"
													IsVisible="{Binding CanHide}"
													Command="{Binding HideToggleCommand}" />
			<Code:ApplicationBarIconButtonDelegate Text="Show"
													IsVisible="{Binding CanShow}"
													Command="{Binding ShowToggleCommand}" />
		</Code:BindableApplicationBar.ButtonDelegates>
		<Code:BindableApplicationBar.MenuItemDelegates>
			<Code:ApplicationBarMenuItemDelegate Text="Random Number Text"
													Command="{Binding ChangeTextMenuCommand}" />
		</Code:BindableApplicationBar.MenuItemDelegates>
	</Code:BindableApplicationBar>
</Code:BindableApplicationBar.BindableApplicationBar>

Once the DataContext of the BindableApplicationBar and all delegate objects are set this code gets run:

private void Initialize(object dataContext)
{
	if (DataContext == dataContext)
	{
		return;
	}

	DataContext = dataContext;

	foreach (var buttonDelegate in ButtonDelegates)
	{
		buttonDelegate.DataContext = DataContext;
		if (buttonDelegate.IsVisible)
		{
			AddAppBarButton(buttonDelegate.Button);
		}
		buttonDelegate.IsVisibleChanged += AppBarButtonIsVisibleChangedHandler;
	}

	foreach (var menuItemDelegate in MenuItemDelegates)
	{
		menuItemDelegate.DataContext = DataContext;
		if (menuItemDelegate.IsVisible)
		{
			AddAppBarMenuItem(menuItemDelegate.MenuItem);
		}
		menuItemDelegate.IsVisibleChanged += AppBarMenuItemIsVisibleChangedHandler;
	}

	UpdateAppBarVisibility();
}

Something that I CANNOT find anywhere, which then became my motivation for writing my own BindableApplicationBar was the ability to have Visibility of the buttons and menu items bound as well as IsEnabled. I added an IsVisible property that drives whether or not the button or menu item is added to the ApplicationBar. Super simple. Also, the delegate objects subscribe to their object’s click event. So one could using Commands and binding, click handlers, or both just like on a normal button.

ApplicationBar.Opacity Fact

Here is an interesting fact for you. The property ApplicationBar.Opacity is 1.0D by default. What I recently learned is that the ApplicationBar.Height is 72px and if Opacity is 1 then the ApplicationBar actually takes up space in the layout of the page. However, as soon as the Opacity is .999D or not equal to 1 then the ApplicationBar no longer participates in the layout of the page. This was a pretty big bummer to the project I’m on since we need to manage our ApplicationBar quite a bit. Wait animations were starting in one spot then moving down after the ApplicationBar would hide. It was very confusing why this was happening until I read about this behavior in the documentation.

So what does all that have to do with the BindableApplicationBar here? Opacity by default is now .999D in order to have a consistent feel across the app. Why .999 not just .9? If .9 is used the ApplicationBar is noticeably transparent, however .999 looks completely Opaque.

Known Issues

The biggest issue I’m aware of right now is the possibility to try and add more than 4 ApplicationBarIconButtons to the ApplicationBar. If the developer adds 5+ button delegates they need to be very careful about managing the visibility of the buttons. Only 4 buttons can be added at a time. The 5th will throw an exception. I’m working on a solution for this, but for now the current version works well enough.

Another nice to have would be the ability to specify permanent order. Currently if 4 buttons are visible and the first is removed (visibility change) and later is readded it will now be the last button. The solution I’m toying with for the above issue would also allow me to fix this one fairly easy as well.

The last major known issue is that DataContext must be set. This means that if the page does not have a DataContext then the the BindableApplicationBar.DataContext property should be set to a string such as BindableApplicationBar.DataContext=”a”. This will cause the logic in Iinitialize(object dataContext) to run (found above).

Sample Code

Finally, the stuff everyone really cares about. Feel free to do whatever you want with the code. I’d love to hear if you’re using it and any feedback you have about the code. Hopefully this is helpful.

BindableApplicationBar Sample Code