This artcile’s sample app provides
the beginnings of a simple data driven e-commerce app that demonstrates
the use of navigation, transient and persistent state, image caching,
and WCF services. It allows the user to select from a list of books,
retrieved from a WCF service, and to view each item’s details on a
separate details page.
The ProductsViewModel
class retrieves a list of Product
objects from a WCF service. Each product has various properties such as a description, price, and an image URI.
The ProductsViewModel
saves and restores its own transient state consisting of the list of products it retrieves from the WCF service (see Listing 1).
The code for this section resides in the
Navigation directory of the WPUnleashed. Examples project in the
downloadable sample code.
The viewmodel’s constructor determines whether transient state exists for itself. If so, it restores the list of Products
or else it requests the list of products from the WCF using the BookshopServiceClient
. The call occurs asynchronously, and the products list is populated after the call completes.
The ViewModelBase
class subclasses the NotifyPropertyChangeBase
class, which implements INotifyPropertyChanged
.
LISTING 1. ProductsViewModel
Class (excerpt)
public class ProductsViewModel : ViewModelBase
{
readonly IDictionary<string, object> transientStateDictionary;
const string transientStateKey = "ProductsViewModel_Products";
public ProductsViewModel(
IDictionary<string, object> transientStateDictionary)
{
this.transientStateDictionary = ArgumentValidator.AssertNotNull(
transientStateDictionary, "transientStateDictionary");
LoadTransientState();
if (products != null)
{
return;
}
BookshopServiceClient client = new BookshopServiceClient();
client.GetProductsCompleted += (sender, args) =>
{
if (args.Error != null)
{
MessageService.ShowError("Unable to retrieve products.");
return;
}
Products = args.Result;
Loaded = true;
};
client.GetProductsAsync();
}
ObservableCollection<Product> products;
public ObservableCollection<Product> Products
{
get
{
return products;
}
private set
{
Assign(ref products, value);
}
}
bool loaded;
public bool Loaded
{
get
{
return loaded;
}
private set
{
Assign(ref loaded, value);
}
}
public void SaveTransientState()
{
transientStateDictionary[transientStateKey] = products;
}
public void LoadTransientState()
{
object transientState;
if (transientStateDictionary.TryGetValue(
transientStateKey, out transientState))
{
products = transientState as ObservableCollection<Product>;
if (products != null)
{
Loaded = true;
}
}
}
}
Within the OnNavigatingTo
method of the ProductsView
page, a ProductsViewModel
is instantiated and assigned to the page’s DataContext
. The ProductsViewModel
is passed the transient state dictionary for the page (see Listing 2).
The OnNavigatingTo
and OnNavigatedFrom
methods are used to inform the viewmodel when to save its state.
LISTING 2. ProductsView
Class
public partial class ProductsView : PhoneApplicationPage
{
public ProductsView()
{
InitializeComponent();
}
ProductsViewModel ViewModel
{
get
{
return (ProductsViewModel)DataContext;
}
}
bool loaded;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
Debug.WriteLine("ProductsView OnNavigatedTo");
base.OnNavigatedTo(e);
if (!loaded)
{
DataContext = new ProductsViewModel(State);
loaded = true;
}
ViewModel.LoadTransientState();
}
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
Debug.WriteLine("ProductsView OnNavigatedFrom");
ViewModel.SaveTransientState();
}
}