Silverlight applications on a Windows Phone use a web-style mechanism for page navigation. Most applications will have at least a few levels of child pages in a hierarchy where a child page represents some sort of activity started by an action on a parent page. In a weather application, clicking on a button to see a specific day of a ten day forecast would show a new page with the day-specific information. Clicking on an hour of that day might show a new page with the forecast for that hour. There would then be three pages in the hierarchy.
A more interesting application might let the user do something on one of those child pages that changes the data shown on one of the parent pages. How does the data get back to the parent in a Silverlight application.
Many people that post about this on the internet mention passing data to a child page using the URI for the page and text parameters. This is fine for text or data that can be easily converted to text. In most cases it is enough. When it comes to passing data back to a parent, global variables are suggested. This might work for a simple app but it’s not a robust solution for anything complicated.
Tombstoning is where an application is deactivated with the expectation that it might be reactivated later. The application needs to act as if it never went away.
This is very interesting because the binary data for the application does go away. All of the pages are gone. The only things that will exist when the application is reactivated is the app object itself and the page that was active when the deactivation occurred. The active page needs to recreate any binary data that is is using from serialized data that it stored when it was last active.
A page doesn’t know that it is being deactivated, just that navigation is leaving the page. When the page doesn’t get a deactivation event makes no sense although it might be the case that the app gets a deactivation event notification at a time when it can set a global variable that the page can then use to know what is happening. The whole tombstone process seems a bit half-assed in many ways, including in this way. It is also hard, but not quite so hard, for the page to know to restore it’s own state when reactivated. It still requires one piece of code saving a bit of state information for another piece of code to use but the state information is kept within the page object and is not global.
My first solution to page navigation was to create an object for each child page activity and store this object on a stack. Code uses the activity on the top of the stack to get parameters and data that is needed on the current page. The code also stored result data in the activity object on the top of the stack as a way of returning data to the parent page.
But what if the parent page can have numerous different child pages? Each different child page is represented by a different type of activity. When an activity object is created for a child page, a callback function delegate is stored in the activity object to be called when the child page is finished. The parent page simply calls the callback function for the current activity when the child is done and things work great. The callback function handles the results of the activity as needed.
But what about tombstoning? I didn’t realize the implications of tombstoning when I designed the activity scheme.
The New Solution
The new solution is the same as the previous solution except for the delegate functions. I could actually get the name of the delegate function as a string and save that for later. C# let’s me find functions by name and call them that way but it’s not really safe in my mind. Still, the callback function concept keeps me from having a bunch of if() tests in the code to examine the activity object type. And isn’t testing the type of an object also a bad coding practice?
Either way, I will test the object type of the activity or call the delegate by name. One of those two things will work fine and remove the need to keep track of binary data like the reference to the callback function.
I will also need to remove code that keep track of the current page for the sake of knowing that an activity is the one for a child. I will need to just make sure that there is an activity for every single possible child page even if the activity is not holding any useful information. Some pages just don’t return data and I was not creating activities for them.
I don’t know if this is a good solution but so far, there does not seem to be a good way to handle this otherwise. I would use global variables but there are too many pages in my app that have too many various results to make global variables a clean solution.