Save and Load Selected Items in a WP8 ListView

I’ve been working on the fit and polish of my new WP8 app and wanted to preserve the selected items of a ListView across page navigations.  This allows the user to navigate to a new page to perform some action and return to the same state they left.

The first step to preserving and restoring state is to create a NavigationHelper instance, and subscribe to the SaveState and LoadState events:

this.navigationHelper = new NavigationHelper(this);
this.navigationHelper.LoadState += this.NavigationHelper_LoadState;
this.navigationHelper.SaveState += this.NavigationHelper_SaveState;

Now you are notified when to save the page state and when to load it.

Saving Selected Indices

There are two ways to save selected items inside the SaveState handler.  The first is to assign the SelectedItems property directly to a key in the PageState property of the event argument.  Inside the LoadState handler, you would then reselect the items in the list. 

Alternatively, you could save the index of each selected item.  This will only work if you guarantee that items won’t change position, but it saves you from searching the collection for each item during the load.

To determine if an item at a given index is selected, you need to check the IsSelected property of the ListViewItem instance.  You can get a ListViewItem for a given index using the method ContainerFromIndex:

private void NavigationHelper_SaveState(object sender, SaveStateEventArgs e) {
	List<int> selected = new List<int>();
	for (int i = 0; i < this._list.Items.Count; i++) {
		if (((ListViewItem)this._list.ContainerFromIndex(i)).IsSelected) {
			selected.Add(i);
		}
	}
	if (0 < selected.Count) {
		e.PageState.Add("SelectedItems", selected);
	}
}

Loading Selected Indices

Loading the indices is a little more difficult because the ListViewItem instance may not be available when the LoadState handler fires.  Instead, you should use the LoadState event to create a handler for the Loaded event of your list.

In the Loaded handler, you can then use the ContainerFromIndex method to get the ListViewItem of each saved index, and set the IsSelected property to true:

private async void NavigationHelper_LoadState(object sender, LoadStateEventArgs e) {
	if (null != e.PageState && e.PageState.ContainsKey("SelectedItems")) {
		
		var list = (e.PageState["SelectedItems"] as List<int>);
		RoutedEventHandler handler = (object sender2, RoutedEventArgs e2) => {
			foreach (int index in list) {
				((ListViewItem)this._list.ContainerFromIndex(index)).IsSelected = true;
			}
		};
 
		this._list.Loaded += handler;
	}
}

Now any selected items will be maintained as the user navigates to and from your page.