How to preserve state across pages in a Windows 8 app

When designing a Windows 8 app, you need a way to preserve the state of various items as you navigate from page to page. Windows allows this using the pageState dictionary - a dictionary that can contain any serializable object. If you're a web programmer, you can think of this as similar to using a session variable. Today I'll add this to the cascading ListBoxes shown earlier. You can download the code for that project at ListBoxDrillDown.zip.

First, we'll add a navigation button to the page. Put the pnlMain StackPanel and the new button inside another StackPanel, like this:

<StackPanel x:Name="pnlContainer" Grid.Row="2" Orientation="Vertical">
    <Button x:Name="btnSearch" Content="Show" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="40,0,0,0" Click="btnSearch_Click"/>
    <StackPanel x:Name="pnlMain" HorizontalAlignment="Left" Margin="20,10" VerticalAlignment="Top" Orientation="Horizontal"/>
</StackPanel>

Then add the Click method:

private void btnSearch_Click(object sender, RoutedEventArgs e)
{
    if (_categoryID > 0)
    {
        this.Frame.Navigate(typeof(LandingPage));
    }
}

LandingPage isn't actually part of the project yet, so go ahead and add it. Just add a Basic Page called LandingPage.xaml to the project. It won't be used for anything other than the back button control.

Now, if you run the app, after you select at least one item in the first ListBox you'll be able to click the button to navigate to the second page. When you click the back button, however, you return with only the first ListBox showing and nothing selected; anything that you had drilled down into will have to be reselected. Let's fix that.

Locate the SaveState method and add the following code:

List<int> list = new List<int>();

for (int x = 1; x <= _listBoxCount; x++)
{
    ListBox lb = (ListBox)pnlMain.Children[x - 1];
    if (lb.SelectedValue != null)
    {
        list.Add(lb.SelectedIndex);
    }
}

pageState["listBoxSettings"] = list;

Here I'm simply adding all the SelectedIndex values to a List and saving it to pageState.

Now, to retrieve this List once we've navigated away and back to the page. Add a variable to the class:

private List<int> _selectionList = null;

Then add the following code to the LoadState method:

if (pageState != null && pageState.ContainsKey("listBoxSettings"))
{
    _selectionList = (List<int>)pageState["listBoxSettings"];
}

CallGetCategoryInfo(_categoryID);

Here I check to see if the "listBoxSettings" key is populated (since this same method will be called the first time the page is loaded, it could be empty...), and then assign it to the variable. Notice that the CallGetCategoryInfo(_categoryID) statement has moved from the ChooseCategory() method; I want to make sure it's called after pageState has been retrieved.

Next, add this code to the AddListBox() method, right before the ListBox is added to the Panel:

if (_selectionList != null && _selectionList.Count >= _listBoxCount)
{
    listBox1.SelectedIndex = _selectionList[_listBoxCount - 1];
}

When a new ListBox is created, I'm checking to see if the ListBox in that position has a selection in the List variable. If so, set the SelectedIndex. The SelectionChanged event will fire again, and the code will check again to see if another selection has already been made.

At this point you should be able to test the app and verify that everything works. Fire it up, drill all the way down in the ListBoxes, go to the next page, and return. You should see all your selections preserved. There's one last thing that we have to do, though. Try this: Drill down as far as you can go into a category, go to the next page and return. Now, at the top level, select a different category. You'll see the app automatically drill down again! This is because the List is still held in the _selectionList variable, and the app doesn't know the difference between a human clicking and the automatic process that happens when we return to the page. The easy way to fix this is to simply clear the List when clicking in a ListBox to the left of another ListBox (i.e. a higher level). Add this code to the ComboBox_SelectionChanged event handler:

_selectionList.Clear();

...inside the for() loop.

Keep in mind, these settings are only going to be preserved while you're using the app - if it's suspended or terminated, they're not available. If you need to preserve them after the app is terminated, you can use the SuspensionManager.

When you hit the back button, you'll probably notice a delay as each new ListBox appears. This is because it's fetching the contents from the eBay API, just as it did the first time you selected it. If you don't like this, then you could simply store the contents of each ListBox in pageState and repopulate.

You can download the code for this at SaveStateDemo.zip.

Technorati Tags: ,,

Print | posted @ Friday, January 4, 2013 11:58 AM

Comments on this entry:

Gravatar # re: How to preserve state across pages in a Windows 8 app
by Anna Holland at 3/5/2013 12:11 PM

Hi Bill,

My name is Anna Holland, and I am a Marketing Coordinator at Syncfusion. I am reaching out to see if you would blog about one of our free e-books, collectively known as the Succinctly series. It is a great way to add value to your personal website. For more information please contact me at annah@syncfusion.com. I look forward to hearing from you!
Post A Comment
Title:
Name:
Email:
Comment:
Verification: