When we originally announced Visual Studio LightSwitch, we introduced a series of blog posts that went under the covers to dive into the anatomy of a LightSwitch application. At that time, this encompassed the end to end solution across the Silverlight client, middle tier and data tier. With the introduction of the HTML client, we wanted to follow up with a similar post looking under the hood of this new client offering.
From an architectural perspective, the LightSwitch HTML client isn’t so different from the existing Silverlight client. It adopts the same logical partitioning – data, screens and shell – and contains all the same concepts, such as entities, screens, content items and controls. This should be of no surprise, since it is based on the same conceptual model and design time experience. Of course, the HTML client looks quite different from a practical perspective. We needed to adopt new frameworks and realize the view layer in terms of the standards-based HTML5 model.
It has always been a core LightSwitch tenet to build applications on top of the same solid foundations you would use to build an application without LightSwitch. In the case of the HTML client, this meant seeking out current or upcoming industry standards for building modern, touch-friendly line of business applications.
The HTML client application stack is divided into five layers based on the MVVM pattern:
- Base. This layer provides functionality used by all the other layers. It mostly builds on and uses the fundamental concepts taken from the WinJS library, such as namespaces, classes, events and promise objects.
- Model. This layer implements loading, parsing and processing of the LightSwitch application model. The model is converted from its original LSML form into a standard JSON representation for quick and easy consumption at application startup.
- Shared. This layer implements the concept of a business object, which, as in the Silverlight client, represents a base for both entities (data) and screens (view models).
- Data. This layer implements the LightSwitch data concepts, including entities, data services and data workspaces. It depends on the datajs library for underlying communication with the LightSwitch OData service.
- View Model. This layer implements the LightSwitch view model concepts, including screens and content items. It also implements the view model for the shell, which includes application-wide commands and the LightSwitch navigation model.
- View. This layer implements the LightSwitch view concepts, including controls, layout primitives and the visualization of the shell. It depends on the jQuery and jQuery Mobile libraries for DOM manipulation and other browser communication.
A New User Experience
When we started working on the HTML client, we evaluated many existing applications on mobile devices to get a sense for how these modern applications operate from a user experience perspective. It quickly became clear that the paradigms exposed by the existing Silverlight shell were not going to be appropriate for a mobile client. Using a number of examples of modern mobile applications, we determined that a few fundamental things had to change:
- SDI instead of MDI. Unlike traditional forms over data applications, modern mobile applications are very task-focused, and it is rare to see any such application with multiple independent tasks running at the same time. From a practical perspective, this means there is exactly one data workspace for the entire application.
- Screen partitioning. The limited real estate on mobile devices simply does not allow for the densely populated screen content typically produced by the Silverlight client. Screens must therefore be split into partitions, allowing only one part of the screen to be viewed at a time.
Further evaluation of these applications led us to believe that a few features missing from the Silverlight client were now quite important in the mobile device space:
- Screen reuse. In the Silverlight client, screens assume ownership of their own data workspace. Hence, no two screens can participate in the same set of pending changes. Higher level tasks or workflows can be simulated across multiple screens by writing code, but these screens communicate independently with the server which is not ideal for an integrated task or workflow. The HTML client’s SDI model has no support for this approach but adds the ability to launch a screen and pass it a context (including a data workspace), allowing it to participate in the same higher level task or workflow.
- Nested changes. The ability to accept or cancel changes that have occurred in a data workspace since a previous checkpoint is a “nice to have” feature in traditional forms over data applications, but it becomes a core requirement for modern mobile applications.
The above described changes led us to develop a few simple extensions to the existing data workspace and screen concepts as well as a new application navigation model.
Tabs and Dialogs
In order to more effectively use the real estate on a mobile device, the HTML client splits a screen into independently viewable partitions. A partition comes in the form of a top-level tab or as a dialog. A user can switch between tabs on a screen like a traditional tab control, and all this does is choose which part of the screen is currently visible. A dialog, on the other hand, temporarily constructs the visual content of the dialog and disposes of it when the dialog is closed.
Here are some screenshots of an example screen “Order Detail” with two tabs, “Details” and “Order Details”, and a dialog “Order_Detail”:
The tab and dialog paradigms provide an effective means of navigating through the content of a single screen, even when that screen has lots of content.
Each time a user moves between tabs in a screen, shows a dialog or shows another screen, a navigation boundary is crossed. There are three boundary options that may be applied at a navigation boundary that affect both the navigation to the target and the return from the target to the source.
The Save boundary option is only applicable when showing another screen:
- Before navigating to the target, if there are changes in the data workspace the user is prompted to save or discard these changes.
- While showing the target, the shell exposes “Save” and “Discard” buttons.
- Before returning from the target, if there are changes in the data workspace the user is prompted to save or discard these changes.
The Nested boundary option is applicable when showing a dialog or another screen:
- Before navigating to the target, a new nested change set is started on the data workspace.
- While showing the target, the shell exposes “OK” and “Cancel” buttons.
- Before returning from the target, if there were changes made the user is prompted to keep or cancel these changes.
The None boundary option is applicable for all navigation scenarios (and is the only option available when moving between tabs in a screen):
- Before navigating to the target, no specific behavior occurs.
- If the target is another screen tab, the shell exposes the previously visible buttons.
- If the target is a dialog or another screen, the shell exposes a “Back” button.
- Before returning from the target, no specific behavior occurs.
Navigation boundary options are configured by the source, making the target ultimately more reusable. For instance, a screen may be the starting point of a new task if launched with a save boundary, or it may be incorporated into an existing task if launched with a nested boundary.
In the LightSwitch design experience, the underlying boundary options are exposed using terminology that emphasizes the task-related capabilities of the target:
Here, “Save” maps to the Save boundary, “OK/Cancel” maps to the Nested boundary option, and “Back” maps to the None boundary option.
One of the biggest differences between Silverlight and HTML as presentation technologies is how content is laid out. In Silverlight, content is designed to fit into a box with bounded width and height. HTML is rooted in an entirely different strategy that comes from its document-based heritage. It assumes that content starts at the top and flows from left to right, then downwards until no content remains. This means that while the width may be bounded, the height is not.
These two layout controls enable the look and feel of a rich web application without introducing significant complexity into the DOM.
A New Approach to Controls
Early on in developing the HTML client, we placed a bet on an emerging technology that was well positioned to take a lead in the HTML-based mobile application space: jQuery Mobile. In choosing this library, we gained functionality for interacting with the browser navigation stack, but more importantly, we picked up a pattern for rendering touch-friendly controls in the browser DOM.
The concept of a “control” is not well defined in the HTML world. From the LightSwitch HTML client perspective, a control is implemented by a function that does two things: it adds elements to the browser DOM that represents the visualization of the control, and then it connects these elements to data through a data binding API. Once this is done, standard jQuery Mobile behavior takes over and expands the DOM into the actual set of elements to be displayed. The result may be significantly different from the original DOM if it referenced a jQuery Mobile control, or it may be left unchanged if the content is entirely custom elements.
This version of the HTML client has a set of built-in controls that are implemented in this fashion, and it also exposes an entry point for LightSwitch developers to provide their own function that implements a new control in the same manner. This does not provide end-to-end integration of specialized control libraries like we had for Silverlight, but almost all HTML control libraries can be easily instantiated and wired up through this custom entry point.
Asynchronous Coding Patterns
In the HTML client, we chose to expose promise objects to represent asynchronous work. Promise objects provide the most flexible set of options when working in an asynchronous environment and make it easier to structure code in its logical order of execution.
There are a number of promise object implementations available. We chose to utilize the WinJS implementation of promise objects as it was one of the more complete offerings and provided technical alignment with the Windows 8 development experience.
In this post, we poked inside the HTML client and discovered how its architecture differs from the existing Silverlight client. Many aspects remain the same between the two runtimes, but the HTML client introduces a few new concepts that were necessary to embrace the target platform.
Senior Developer, LightSwitch Team