Background
Diner Silverlight is a Windows Phone port of Diner implemented with QML. See the porting notes here.
Design approach
The Diner application utilises panorama control. Because of this, the application is locked to portrait mode most of the time, apart from the food menu and the reservation form. Even though Diner follows the Metro guidelines in design, the look and feel can easily be tailored to adapt the brand of a specific restaurant by changing the logo, the background of the panorama, and of course the textual information.
Deviations from original design
During implementation, the user experience of the application was evaluated iteratively and it was observed that the user experience could be enhanced by slightly modifying the original design. As a result the following changes were made:
- Originally an embedded map view describing the immediate surroundings of the restaurant was to be shown to the user in the 'Location' view. It was however observed that embedding a map view significantly increased the loading time of the application. It was also observed that the size of the embedded map was too small for the user to use it effectively for navigation. Due to these reasons, the embedded map view was replaced with an icon describing a map (accompanied with the text 'View map'). When the user presses the icon, a dedicated, full-screen map view centered on the restaurant is shown.
- In the original design, the cancellation of a reservation required a confirmation by the user. Cancellation is possible through a context menu that is opened by long-tapping the reservation in the 'Reservations' view. Because it is highly unlikely that the user would accidentally both long-tap the reservation and click 'Cancel' in the context menu, confirmation of this action was deemed unnecessary and was removed.
- In the original design, reservations shown in the 'Reservations' view could not be modified. This was unintuitive to the user: even though visual feedback in the form of a tilting effect is displayed for reservations shown in the list, the only option the user had for interacting with the reservations was long-tapping them in order to bring up a context menu. This behaviour was changed by introducing a new feature where users could modify existing reservations by clicking them.
Implementation approach
Application data
Diner Silverlight is about viewing the details of a single restaurant, so the data model of the application consists solely of this data. The restaurant data can be divided into two contexts:
- Details of the restaurant, such as restaurant name, contact information, and menu. Since this information is static, it is loaded from an XML file shipped with the application.
- Information describing the reservations. Since the user can manipulate this information, it persists on disk separate from the restaurant details.
The view model of the application is encapsulated in the MainViewModel
class and it acts as the data context for the majority of the application's views. Several other classes, such as RestaurantData
, Reservation
, and Dish
, are used to model the restaurant data. MainViewModel
is responsible for loading and saving application data, and creating data model classes as required.
Restaurant details contained in data model classes are object properties, and all data model classes implement the INotifyPropertyChanged
interface. This makes it easy to publish this information to the user using XAML data-binding.
Reading restaurant XML file
Reading of the XML file that contains the restaurant description is implemented by the LoadXML()
method of MainViewModel
. Parsing is done using LINQ as it allows easy generation of data model instances from the parsed data. This is visible especially when restaurant menu information is parsed:
XElement menu = doc.Descendants("menu").First();
Restaurant.Categories = (from category in menu.Descendants("category")
select new Category()
{
Id = category.Attribute("id").Value,
Name = category.Attribute("name").Value,
IconURI = category.Attribute("icon").Value,
Dishes = (from dish in category.Descendants("dish")
select new Dish()
{
Name = dish.Attribute("name").Value,
Text = dish.Value
}).ToList<Dish>()
}).ToList<Category>();
Storing reservations
The loading and saving of reservations is implemented by the LoadReservations()
and SaveReservations()
methods of MainViewModel
. A single file is used to store reservations on disk. The reading and writing of this file is accomplished using 'data contracting', where DataContractSerializer
offered by the Silverlight framework is able to serialise between run-time objects and XML. A single reservation is represented by the Reservation class. This class includes necessary DataContract
and DataMember
tags that describe how the class should be serialised.
private void LoadReservations()
{
using (IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream("reservations.dat", System.IO.FileMode.OpenOrCreate, file))
{
if (stream.Length > 0)
{
DataContractSerializer serializer = new DataContractSerializer(typeof(ObservableCollection<Reservation>));
Restaurant.Reservations = serializer.ReadObject(stream) as ObservableCollection<Reservation>;
}
}
}
}
private void SaveReservations()
{
using (IsolatedStorageFile file = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream("reservations.dat", System.IO.FileMode.Create, file))
{
DataContractSerializer serializer = new DataContractSerializer(typeof(ObservableCollection<Reservation>));
serializer.WriteObject(stream, Restaurant.Reservations);
}
}
}
User interface
During the implementation of the UI it became apparent that the Windows Phone 7.0 platform does not offer support to many features that might be considered commonplace in other mobile platforms. For example, the user should be able to move to the map/navigation program of the platform when he/she clicks the map icon in the 'location' view of the application. Unfortunately the Windows Phone 7.0 platform does not offer a launch task to accomplish this. This issue was worked around by showing the restaurant map using a Silverlight map control embedded into a separate fullscreen view of the application. The downside of this approach is that the user will not be able to use the map view to navigate to the restaurant from his/her current position. Even though a Bing Maps launcher was introduced in Windows Phone OS 7.1, the same separate fullscreen view approach is used to show the new Map Control in Windows Phone 8 port of the application.
Also, the Windows Phone platform does not offer many of the UI controls used widely in the applications that ship WITH the phone. For example, controls for picking a time and/or date (as required when making a new reservation) and listbox context menus (as required when removing a reservation) do not ship with the base SDK. Fortunately these controls were available in the SilverLight Toolkit, which was taken into use in the project. Silverlight Toolkit also offers many other features that can be used to enhance user interfaces, such as a tilt effect for pushable controls.
Launching external applications
In addition to launching a map around the restaurant location, the user is also able to view the restaurant's web page using a browser and/or initiate a phone call to the restaurant from the 'location' view of the application. Both features are implemented by using the HyperLinkButton
control. Launching a browser is the simpler one of the two procedures: HyperLinkButton
only needs its NavigateUri
property to be set to point to the restaurant's web page and the browser is automatically launched. Directly initiating a phone call via HyperLinkButton
is not possible, instead a button click handler needs to be registered to the control. This click handler creates a PhoneCallTask
object which initiates the call.
Tombstoning
Diner saves both persistent and transient data upon changes in application life cycle to ensure a good user experience. Persistent data saved by the application consists of reservation data for the restaurant. The saving of reservations is triggered by the Application_Deactivated()
and Application_Closing()
callbacks. Transient data is saved for each UI page/view in OnNavigatedFrom()
to the callback of each view. Loading of reservations is only delayed immediately before the data is needed (usually this happens when the OnNavigatedTo()
callback of the UI view needs the data). Transient data is loaded for each UI page/view in the OnNavigatedTo()
callback of each view.
It should be noted that the panorama and pivot controls that ship with Windows Phone have issues related to restoring their state in application activation. Pivot control suffers from crashing issues if the last pivot page viewed by the user is restored too soon. Panorama control on the other hand does not directly support restoring the last panorama view viewed by the user; instead it only supports setting a panorama view as a 'default view' which alters the position of the panorama's background image.
Bing Maps key in Diner for WP 7
Diner for WP 7 features a Silverlight map control based on the Bing Maps service. The usual practice when using the Bing Maps service is to register a developer key that is embedded to the application, so that usage statistics can be collected, for example. However, as Diner is just an example application, no developer key is registered for it. This leads to the text 'Invalid credentials. Sign up for a developer account' being shown on top of the map control. This does not affect the functionality of the map control and is just a visual nuisance. For an actual application intended for deployment through the Marketplace, a developer key should be embedded to the application. More details are available here.
Porting to Windows Phone 8
The Diner application has been upgraded to support new Windows Phone 8 Map control while retaining compatibility with Windows Phone 7 and Bing Maps. Porting to WP 8 was made according to the guidelines laid out in the article Lumia Library Co-Development and Porting Guide. Following techniques, described in more detail in the article, were used for implementing the multi-platform support for Diner application:
- Two top-level projects (separate projects for WP 7 and WP 8 in a single solution)
- Using linked source code files (WP 7 and WP 8 projects share the same code base)
- Compile-time adaptation (isolating the platform specific maps related code)