Nov
23
Written by:
Michael Washington
11/23/2013 5:18 PM
The LightSwitch Extensibility Toolkit for Visual Studio 2013 allows you to create reusable HTML client screen templates. This is a very powerful feature in that you have full control of the generated HTML and JavaScript. In your screen template code you have the ability to interrogate the (optional) entity or collection specified by the end user, and create a screen design based on what they select.
Creating Visual Studio LightSwitch HTML Client screen templates is surprisingly easy. It is hard to think of any other tool that allows an end user developer to create a HTML SPA application where they only have to define their data model and are able to implement custom JavaScript components and not have to write any JavaScript themselves, yet have the option to alter the JavaScript that is written.
To get a good idea of how LightSwitch HTML Screen Templates work, start with the following article: Creating A LightSwitch HTML Screen Extension.
In this article we will cover the core aspects of the API to assist you in creating your own templates. You can use the templates for your own use or distribute them to others as an installable package in Visual Studio.
The screen template Application Programming Interface (API) is covered in the following official documentation: Creating a LightSwitch Screen Template, however that primarily covers the Silverlight screen template and in this article we will cover the parts specific to the HTML screen template.
Planning Your Screen Template
When you plan to create a LightSwitch HTML Screen Template, it may help to use the following guide:
- Root Data Source - Your template can allow the end user developer to specify a primary data source and optionally one or more related child data entities. The types are:
- None – You do not have to allow a data source to be specified. This is useful when creating a template that implements just JavaScript components or screen layouts. The end user developer will still be able to add collections and entities to the screen.
- Collection – This is multiple entities, basically a table in LightSwitch, or a query that returns multiple records.
- NewEntity – The template will be used to allow a user to create a new record in a table.
- ScalarEntity – The template will be used for one record (one row of data) in a table or a query that returns one record.
- Layout / Containers (Group) – These elements lay out your screen. Keep in mind that they are designed to allow the screen to adjust to multiple form factors.
- General layouts: Rows Layout, Columns Layout
- Data Collection layouts: DataGrid, List, and TileList
- Commands – These perform actions such as executing JavaScript. The types are: Button, Link, ShellButton, and CollectionButton
- Screen Content (Custom Control) – This is basically a placeholder for you to implement custom HTML.
- Custom JavaScript - This is the most powerful feature of LightSwitch Screen Templates. You can implement any JavaScript that you require.
The diagram above shows the various elements in the screen designer.
The diagram above shows the various elements in the running application.
If you right-click on the screen in the Solution Explorer and select Open With…
… and select the Source Code editor…
You will see the structure that will also contain the important LightSwitch Control ViewIDs that you will need when constructing your own screen templates.
You will find that the best way to make Screen Templates is to first make the screen and JavaScript in a normal LightSwitch project, then examine the .lsml file to see what your Screen Template needs to create.
A Simple Template That Does Nothing
To help understand exactly what creating a screen extension does, we will start by creating a screen template that does nothing. Follow the directions here:
http://lightswitchhelpwebsite.com/Blog/tabid/61/EntryId/3239/Creating-A-LightSwitch-HTML-Screen-Extension.aspx to create a screen template.
As with all LightSwitch HTML Screen templates we update the class decorators to specify “MobileWeb”.
We also set the ScreenEditMode to Browse so that the save button does not appear on the screen when the application is running. However, the end user designer can change this if they want.
We also add the following using statement to the class file:
using Microsoft.LightSwitch.DesignTime;
We set the RootDataSource to None.
This means the template will not allow the end user developer to select a primary data source for the screen when they use the template. However, the end user can add a data source to the screen after it is created.
We also set SupportsChildCollections to false because we are not allowing a data source in this situation. If we had allowed a data source, setting this to true would allow the end user designer to select additional data sources that have some relation set to the primary data source they select.
We leave the Generate method blank.
When we run the template in a test version of Visual Studio we see that it creates a screen that has a Screen container that contains Tabs and Popups containers.
Tabs – These are visual layouts that appear one at a time. They are switchable by the end user when their labels are set to show (you can hide them).
Popups – These are visual layouts that appear on top of Tabs and can be closed or dismissed by the end user by clicking outside of the popup.
Because we only have containers on the screen, no actual elements, the screen would be blank. The end user developer can add any data sources and elements they want.
Using Groups
To make the template generate content we place code in the Generate method of the class file for our template. We notice that the method has a parameter called host of type IScreenTemplateHost. We will use this to create our screen template content.
The IScreenTemplateHost object has a number of methods and properties to allow you to add content and discover any configured data sources.
If there is a purple box next to the item it is a method, meaning it “does something” for example:
- addContentItem – This will add visual or HTML content to the screen like a group or Tile List.
- addScreenCodeBehind – This will create JavaScript that the screen template can use. It is the most powerful function and will be explored in the last section of this article.
- addScreenMethod – This is used to add a method to the view model (shown on the left-hand side of the screen designer). You would still need to use addScreenCodeBehind to add code for this method.
- addScreenProperty - This is used to add a property to the view model (shown on the left-hand side of the screen designer).
If there is a black wrench next to an item it is a property meaning it “has a value” you can use for example:
- ScreenTabPagesContentItem – The root of the Tab group. Use this value to append additional content.
- ScreenDialogPagesContentItem - The root of the Popup group. Use this value to append additional content.
- PrimaryDataSourceProperty – The data source selected by the end user designer. Use this value to bind visual elements such as a List or a text box.
We will now use the AddContentItem method, The AddContentItem method has the following signatures:
- ContentItem AddContentItem(ContentItem parent, string suggestedName, ContentItemKind kind);
- ContentItem AddContentItem(ContentItem parent, string suggestedName, ScreenMethod screenMethod);
- ContentItem AddContentItem(ContentItem parent, string suggestedName, ScreenPropertyBase screenProperty);
- ContentItem AddContentItem(ContentItem parent, string suggestedName, ContentItemKind kind, ChainExpression dataSourceExpression, IDataType dataType);
- ContentItem AddContentItem(ContentItem parent, string suggestedName, ContentItemKind kind, ChainExpression dataSourceExpression, string dataTypeId);
We can add a Tab to the screen using the code above.
We can add a Popup using the code below:
// Add screen Popup
host.AddContentItem(host.ScreenDialogPagesContentItem, "MyPopup", ContentItemKind.Group);
When we implement the template we see that the groups show.
Using Data
LightSwitch uses a data driven workflow. The end user developer is expected to define the data for their application first and then make screens based on that data. Making scree templates that respond to the data selected is an important function of a Screen Template.
We create a new Screen Template called SimpleTileList.
We set the RootDataSource to Collection but SupportsChildCollections to false so that the template will only ask for a single collection (again, remember the end user developer can change the final screen to be anything they want).
public RootDataSourceType RootDataSource
{
get { return RootDataSourceType.Collection; }
}
public bool SupportsChildCollections
{
get { return false; }
}
In the Generate method we add the following code:
// Determine if a PrimaryDataSourceProperty was selected
if (null != host.PrimaryDataSourceProperty)
{
}
Inside this block we add:
// Get the ScreenCollectionProperty that was selected by the end user
ScreenCollectionProperty collectionProperty =
(ScreenCollectionProperty)(host.PrimaryDataSourceProperty);
// Cast the collectionProperty that was selected by the end user to a primaryDataType
IDataType primaryDataType =
host.FindGlobalModelItem<ISequenceType>(collectionProperty.PropertyType).ElementType as IDataType;
This provides programmatic access to the data source.
The following code will create a tab that will have the selected data source in its name:
// Construct a name to use for the Tab using the name of the data source
string tabName = primaryDataType.Name + "TileList";
// Add a Tab to the screen
// Get a tabContentItem that additional content will be added to
ContentItem tabContentItem =
host.AddContentItem(host.ScreenTabPagesContentItem, tabName, ContentItemKind.Group);
Next, we have code that will deal with the fact that a data source can have required parameters, for example a PreProcess Query.
The following code is used:
// Add the query parameters of the data source to the tab content item
// if there are any
if (null != host.PrimaryDataSourceParameterProperties)
{
// Loop through each parameter of the data source
foreach (ScreenPropertyBase parameter in host.PrimaryDataSourceParameterProperties)
{
// Add the element to the screen so the end user can provide a value
// for the parameter
ContentItem contentItem =
host.AddContentItem(tabContentItem, parameter.Name, parameter);
}
}
If the query took a CustomerAge parameter, the output on the screen would look like this:
Lastly the following code is used to display the selected collection in a Tile List:
// Add a control to tabContentItem to display the data
ContentItem listContentItem =
host.AddContentItem(tabContentItem, primaryDataType.Name, host.PrimaryDataSourceProperty);
// Set the type to a Tile List
listContentItem.View = "Microsoft.LightSwitch.MobileWeb:TileList";
// Call ExpandContentItem to create a element to represent fields in the collection (table)
// disableNavigationPropertyGeneration - indicates if navigation to an associated table is shown
// disableGeneratedPropertyGeneration - indicates if automatic fields (like the audit fields) are shown
host.ExpandContentItem(listContentItem, disableNavigationPropertyGeneration: false,
disableGeneratedPropertyGeneration: false);
When the template is used, the end user developer can select a primary data source.
The screen template is generated.
Using JavaScript
The most powerful aspect of HTML Screen Templates is the ability to create custom JavaScript based on the data sources selected by the end user developer.
To create the JavaScript we simply need to call the addScreenCodeBehind method. The key is to create this code so it is wired up to the data sources selected by the end user developer. We do this by programmatically examining the data source selected by the end user developer and passing parameters to the code generation method.
Our custom JavaScript will fall into the following categories:
- JavaScript function – We can write any JavaScript to the screen. However, remember that other screens in the application can use the same screen template so we want to create names for any JavaScript functions and variables that contain the name of the current screen to avoid conflicts.
- _postRender - Used to add a CSS, DOM attributes, or attach JavaScript to existing DOM elements.
- _render - Allows you to programmatically create and insert an arbitrary set of DOM elements, or attach JavaScript (see an example of this in: Creating A LightSwitch HTML Screen Extension).
In this final example, we will create a Screen Template that will allow the end user developer to select a primary data source and a secondary data source and display how many records are in the associated table for each record in the primary data source.
The first step is to create the functionality we desire in a normal LightSwitch project.
We then examine the JavaScript created.
In our screen template we use code such as the following to create our simple JavaScript function:
// Create JavaScript code for Utility function
string UtilityTemplate = "";
UtilityTemplate = UtilityTemplate + "{0}function CountEntities_{1}(Entities) {{";
UtilityTemplate = UtilityTemplate + "{0} var TotalEntities = 0; ";
UtilityTemplate = UtilityTemplate + "{0} var Entities = Entities.results; ";
UtilityTemplate = UtilityTemplate + "{0} var TotalEntities = 0; ";
UtilityTemplate = UtilityTemplate + "{0} Entities.forEach(function (entity) {{ ";
UtilityTemplate = UtilityTemplate + "{0} TotalEntities = TotalEntities + 1; ";
UtilityTemplate = UtilityTemplate + "{0} }}); ";
UtilityTemplate = UtilityTemplate + "{0} return TotalEntities; ";
UtilityTemplate = UtilityTemplate + "{0}}}";
// Call AddScreenCodeBehind for UtilityTemplate
host.AddScreenCodeBehind(String.Format(UtilityTemplate, Environment.NewLine, host.ScreenName));
We use the following code to implement a function that will create JavaScript for each row of data.
This code will make an OData call and get the count of associated records:
// Check if there were any related tables
if (host.ChildCollectionProperties.Count > 0)
{
// Get name of Primary table
string PrimaryTableName = primaryDataType.Name;
// Get the related table name
ScreenCollectionProperty ChildcollectionProperty =
(ScreenCollectionProperty)(host.ChildCollectionProperties[0]);
string RelatedTableName = ChildcollectionProperty.Name;
// If the Table ends with Collection replace it with Set
if(RelatedTableName.EndsWith("Collection"))
{
RelatedTableName = RelatedTableName.Replace("Collection", "Set");
}
// Create JavaScript code for _postRender of the List
// ** Note: This sample code only works for intrinsic LightSwitch data sources
StringBuilder sb = new StringBuilder();
sb.Append("{0}myapp.{1}.RowTemplate_postRender = function (element, contentItem) {{ ");
sb.Append("{0} var {2} = contentItem.value; ");
sb.Append("{0} var Id = {2}.Id; ");
sb.Append("{0} var Int32 = ':Int32'; ");
sb.Append("{0} var filter = '({2}/Id eq ' + msls._toODataString(Id, Int32) + ')'; ");
sb.Append("{0} myapp.activeDataWorkspace.ApplicationData.{3} ");
sb.Append("{0} .filter(filter) ");
sb.Append("{0} .execute() ");
sb.Append("{0} .then(function (result) {{ ");
sb.Append("{0} element.innerText = element.innerText + ' ");
sb.Append("(Number of {3}: ' + CountEntities_{1}(result) + ')'; ");
sb.Append("{0} }}) ");
sb.Append("{0}}}; ");
// Call AddScreenCodeBehind for postRenderTemplate
host.AddScreenCodeBehind(String.Format(sb.ToString(),
Environment.NewLine,
host.ScreenName,
PrimaryTableName,
RelatedTableName));
}
When we implement the Screen Template we will be able to select a table and an associated collection.
The screen will be created.
The JavaScript will be created.
The page will display.
Next Step
Creating Advanced LightSwitch HTML Screen Templates
Special Thanks
This article would not be possible without extensive assistance of LightSwitch team member Justin Anderson. However, any mistakes are my own.
Links
Creating a LightSwitch Screen Template
LightSwitch Extensibility Toolkit for Visual Studio 2013
LightSwitch Screen Template Extension Sample for Visual Studio 2013
Microsoft Visual Studio 2013 SDK (Download)
LightSwitch Extensibility Toolkit for Visual Studio 2013 (Download)
How to: Create a LightSwitch Extension Project
How to: Debug or Test a LightSwitch Extension
How to: Set VSIX Package Properties
How to: Distribute a LightSwitch Extension
Download
The LightSwitch project is available at http://lightswitchhelpwebsite.com/Downloads.aspx
(you must have Visual Studio 2013 Professional (or higher), Visual Studio 2013 SDK, and LightSwitch Extensibility Toolkit for Visual Studio 2013 installed to run the code)
2 comment(s) so far...
Hi I'm new in this world of MS LightSwitch, I do have some experience using VB.NET with Visual Studio 2010,2012,2013 And I,m been testing with MS LightSwitch and I know this tool give us greate help from the developer site and one thing that I found is the Choice List in a table, but what happens if I want to read values that behave the same as a choice list, How do I setup that in my project???
Please provide any example project if you have.
Thanks
By Carlos on
2/15/2014 7:59 AM
|
@Carlos - For help with LightSwitch questions please use the Official LightSwitch forums at: http://social.msdn.microsoft.com/Forums/vstudio/en-US/home?forum=lightswitch
By Michael Washington on
2/15/2014 8:16 AM
|