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 ListBox
es shown earlier. You can download the code for that project here.
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 ListBox
es, 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 here.