Creating a LightSwitch Screen Template

LightSwitch includes templates that can be used to create screens that have common patterns. You can also develop templates that you can use with a specific data source, or with any data type.

A screen template generates data and controls for a screen, based on information that a developer specifies in the Add Screen dialog box. Screen templates can also be programmed to add code for the screen.

The techniques for creating HTML Client screen templates are similar to those shown here for Desktop Client screen templates. The primary differences are the ViewIDs, which differ for each client type. See LightSwitch Control ViewIDs.

Note

This document demonstrates a variety of scenarios that can be accomplished in screen templates, but it does not show how to produce an actual template that you can reuse. You can use these scenarios as best practices when you create templates. You can download a sample that contains both Desktop Client and HTML Client templates from the MSDN Code Gallery.

Define the Screen Template

To create a screen template, first create a project by using the LightSwitch Extension Library project template, which is provided by the LightSwitch Extensibility Toolkit for Visual Studio 2013. When you create the project, select either Visual Basic or C# as the development language.

To define a screen template

  1. In Solution Explorer, choose the LibraryName.Lspkg project, where LibraryName is the name of your extension project.

  2. On the menu bar, choose Project, Add New Item.

  3. In the Add New Item dialog box, choose LightSwitch Screen Template.

  4. In the Name box, enter a name for the screen template. This is the name that developers will see in the Add Screen dialog box.

  5. Choose the OK button.

    A class that represents the screen template is added to ScreenTemplates folder in the Design project. The TemplateName.vb or TemplateName.cs file contains all of the code for the template. All of the examples in this document are in that file.

    Two image files are also added to the project, in the Resources\ScreenTemplateImages folder. These represent the images that will be displayed for the template in the Add Screen dialog box.

Specify a Display Name and Description

The DisplayName and Description properties provide the name and description that are displayed for the screen template in the Add Screen dialog box.

The following example shows the Description and DisplayName properties that are generated for a screen template named “Test Template”; you should change these to a meaningful name and description.

Public ReadOnly Property Description As String Implements IScreenTemplateMetadata.Description
            Get
                Return "Test Template Description"
            End Get
        End Property

        Public ReadOnly Property DisplayName As String Implements IScreenTemplateMetadata.DisplayName
            Get
                Return "Test Template"
            End Get
        End Property
public string Description
        {
            get { return "TestTemplate Description"; }
        }

        public string DisplayName
        {
            get { return "Test Template"; }
        }

Specify the Root Data Source

The RootDataSource property determines what types of data can be displayed by the screen template. The data types will be available in the Screen Data option in the Add Screen dialog box. The RootDataSource property has four valid values:

Collection

Enables the selection of collections or multiple result queries.

ScalarEntity

Enables the selection of one entity type, or queries that return one item.

NewEntity

Used for screens that are intended to enable creating new entities.

None

Used for screens in which no data is to be selected.

The following example shows Collection specified as the RootDataSource.

Public ReadOnly Property RootDataSource As RootDataSourceType Implements IScreenTemplateMetadata.RootDataSource
            Get
                Return RootDataSourceType.Collection
            End Get
        End Property
public RootDataSourceType RootDataSource
        {
            get { return RootDataSourceType.Collection; }
        }

Determine Support for Child Collections

In some situations, a screen template may have to display data that is related to the root data for the screen. For example, a screen template that is displaying an Order may also have to display related Order Lines. To enable this functionality, set the SupportsChildCollections property. If you set it to True, any related collections for the root data type will be displayed in the Add Screen dialog box so that a developer can decide whether to include them in a screen.

The following example shows the SupportsChildCollections property set to True; to disable child collections you should change this to False:

Public ReadOnly Property SupportsChildCollections As Boolean Implements IScreenTemplateMetadata.SupportsChildCollections
            Get
                Return True
            End Get
        End Property
public bool SupportsChildCollections
        {
            get { return true; }
        }

Generate a Screen Content Tree

Typically, most of the code for a screen template is in the Generate method. This method can be used to add data, code or controls to screens that are based on the template. LightSwitch provides basic screen elements such as screen commands. You can modify the content item hierarchy and create elements by using available storage model classes such as ContentItem and all its related classes.

LightSwitch provides a reference to the screen template generator host, which provides functionality that the generation code can use when it creates a screen. Some of this functionality is only available by using the host. If you are not sure which structures you should create, we recommend that you create an example screen in LightSwitch and then inspect the .lsml file in the project’s Common folder to see how LightSwitch generated it.

Add a Content Item for the Root Data of a Screen

A content item represents a LightSwitch control on the screen. The following code in the Generate method shows how to add a content item to the root of the screen for the primary data member of the screen. This could be a collection or single entity, depending on the type of screen template.

Dim primaryDataControl As ContentItem = host.AddContentItem(host.ScreenLayoutContentItem, host.MakeUniqueLegalNameForContentItem("My Root Data"), host.PrimaryDataSourceProperty)
ContentItem primaryDataControl = host.AddContentItem(host.ScreenLayoutContentItem, host.MakeUniqueLegalNameForContentItem("My Root Data"), host.PrimaryDataSourceProperty);

Specify a Specific Control to Use for a Content Item

controls are identified by a ViewID, which is a combination of the name of the control and the name of the module where it is defined. For a list of ViewIDs, see LightSwitch Control ViewIDs.

The following code shows how to specify the control type of the ContentItem as a DataGrid.

host.SetContentItemView(primaryDataControl, "Microsoft.LightSwitch.RichClient:DataGrid")
host.SetContentItemView(primaryDataControl, "Microsoft.LightSwitch.RichClient:DataGrid");

LightSwitch uses smart defaults for things such as the control to use for a particular content item and its default property values. Smart defaults also consider the data type of a control, where it is in the content tree, what controls are its parents, and so on. If you set a content item to a specific control, LightSwitch honors that choice instead of using defaults (unless it is not valid). The data type of a particular field may be a custom type that you know nothing about, and have a default mapping to a control you know nothing about. Additionally, a developer may be able to override the controls that are selected by default for certain situations. Therefore, we recommend that you set a specific control for a content item only if you want that specific control to be used in all cases.

Expand the Children of a Content Item

It is frequently necessary to expand a content item by adding children for all fields in its bound entity. We recommend that you call host.ExpandContentItem to accomplish this instead of doing it manually. This call generates the default children for that control automatically, in a consistent and correct manner. In the following example, ExpandContentItem adds the default child (the DataGridRow) to the DataGrid. It also adds the default children to the DataGridRow. This resembles the use of Reset in the LightSwitch screen designer.

host.ExpandContentItem(primaryDataControl)
host.ExpandContentItem(primaryDataControl);

Set Properties on a Control to Non-Default Values

LightSwitch supports an inheritance pattern for controls. Properties can be defined at different levels in the inheritance hierarchy. For example, all LightSwitch controls inherit from Microsoft.LightSwitch.RichClient:RootControl, which has common properties for control sizing (horizontal and vertical alignment, height and width, and so on). To set a property on a control, you have to know which control type that property was defined on. For a list of built-in LightSwitch control properties, see Defining, Overriding, and Using LightSwitch Control Properties.

The following example sets VerticalAlignment and HeightSizingMode properties on a screen control.

host.SetControlPropertyValue(primaryDataControl, "Microsoft.LightSwitch.RichClient:RootControl", "VerticalAlignment", "Top")
            host.SetControlPropertyValue(primaryDataControl, "Microsoft.LightSwitch.RichClient:RootControl", "HeightSizingMode", "Auto")
host.SetControlPropertyValue(primaryDataControl, "Microsoft.LightSwitch.RichClient:RootControl", "VerticalAlignment", "Top");
            host.SetControlPropertyValue(primaryDataControl, "Microsoft.LightSwitch.RichClient:RootControl", "HeightSizingMode", "Auto");

We recommend that you set values for properties only if you require that those specific values must be used, because doing this keeps LightSwitch from determining default values for the properties based on their context in the screen content tree.

Set the Display Name for a Content Item or Screen Member

The following example sets the display name for a content item. The example could also be used to set the display name for a screen member.

host.SetDisplayName(primaryDataControl, "Main Screen Data")
host.SetDisplayName(primaryDataControl, "Main Screen Data");

If no display name is set, LightSwitch provides a default display name, based on the data that the content item is bound to.

Set Properties on Screen Data Members

The following example sets the DisablePaging property on a screen data member. ScreenCollectionProperty represents a collection screen member; ScreenProperty represents a scalar type (entity or simple data type).

DirectCast(host.PrimaryDataSourceProperty, ScreenCollectionProperty).DisablePaging = True
((ScreenCollectionProperty)host.PrimaryDataSourceProperty).DisablePaging = true;

Add Screen Members

The following example adds a string property to the screen.

' Add a screen member.
            Dim screenProperty As ScreenProperty = host.AddScreenProperty("Microsoft.LightSwitch:String", "NewScreenProperty")
// Add a screen member.
            ScreenProperty screenProperty = host.AddScreenProperty("Microsoft.LightSwitch:String", "NewScreenProperty") as ScreenProperty;

Display the Selected Item of a Collection

The following example adds the selected item of a screen collection to the screen.

' Get the data type of your property.
            Dim collectionProperty As ScreenCollectionProperty = DirectCast(host.PrimaryDataSourceProperty, ScreenCollectionProperty)
            Dim collectionDataType As IEntityType = host.FindGlobalModelItem(Of ISequenceType)(collectionProperty.PropertyType).ElementType

            ' Create an expression that represents accessing the selected item on your collection property.
            Dim chain As ChainExpression = host.CreateChainExpression(host.CreateMemberExpression(collectionProperty.Id))
            host.AppendMemberExpression(chain, "SelectedItem")

            ' Add a content item representing the selected item and set its view to a RowsLayout.
            Dim detailControl As ContentItem = host.AddContentItem(host.ScreenLayoutContentItem, "ItemDetail", ContentItemKind.Details, chain, collectionDataType)
            host.SetContentItemView(detailControl, "Microsoft.LightSwitch.RichClient:RowsLayout")
            host.SetControlPropertyValue(detailControl, "Microsoft.LightSwitch.RichClient:RootControl", "VerticalAlignment", "Top")
            host.ExpandContentItem(detailControl)
// Get the data type of your property.
            ScreenCollectionProperty collectionProperty = (ScreenCollectionProperty)(host.PrimaryDataSourceProperty);
            IEntityType collectionDataType = host.FindGlobalModelItem<ISequenceType>(collectionProperty.PropertyType).ElementType as IEntityType; 
// Create an expression that represents accessing the selected item on your collection property.
            ChainExpression chain = host.CreateChainExpression(host.CreateMemberExpression(collectionProperty.Id));
            host.AppendMemberExpression(chain, "SelectedItem");

            // Add a content item representing the selected item and set its view to a RowsLayout.
            ContentItem detailControl = host.AddContentItem(host.ScreenLayoutContentItem, "ItemDetail", ContentItemKind.Details, chain, collectionDataType);
            host.SetContentItemView(detailControl, "Microsoft.LightSwitch.RichClient:RowsLayout");
            host.SetControlPropertyValue(detailControl, "Microsoft.LightSwitch.RichClient:RootControl", "VerticalAlignment", "Top");
            host.ExpandContentItem(detailControl);

Add a Group Control

The following example adds a group control the screen.

'Add a tabs group to the screen.
            Dim tabsGroup As ContentItem = host.AddContentItem(host.ScreenLayoutContentItem, "TabsGroup", ContentItemKind.Group)
            host.SetContentItemView(tabsGroup, "Microsoft.LightSwitch.RichClient:TabsLayout")
// Add a tabs group to the screen.
            ContentItem tabsGroup = host.AddContentItem(host.ScreenLayoutContentItem, "TabsGroup", ContentItemKind.Group);
            host.SetContentItemView(tabsGroup, "Microsoft.LightSwitch.RichClient:TabsLayout");

Additional related collections may be added to the screen if the developer specifies it. For example, the developer might want to include OrderLines when Orders are displayed. The following example shows how to add related collections to the screen. Notice that this code requires that you have already added the code shown in the previous example, "Add a Group Control".

For Each p As ScreenCollectionProperty In host.ChildCollectionProperties
                'Display each child collection as a grid.
                Dim currentTab As ContentItem = host.AddContentItem(tabsGroup, host.MakeUniqueLegalNameForContentItem("Tab"), p)
                host.SetContentItemView(currentTab, "Microsoft.LightSwitch.RichClient:DataGrid")
                host.ExpandContentItem(currentTab)
            Next
foreach (ScreenCollectionProperty p in host.ChildCollectionProperties)
            {
                // Display each child collection as a grid.
                ContentItem currentTab = host.AddContentItem(tabsGroup, host.MakeUniqueLegalNameForContentItem("Tab"), p);
                host.SetContentItemView(currentTab, "Microsoft.LightSwitch.RichClient:DataGrid");
                host.ExpandContentItem(currentTab);
            }

Add Query Parameters

If the primary data selected for the screen is a query, it may contain parameters. The following example demonstrates how to add parameters to a screen.

'Add parameters to the screen.
            Dim parameterGroup As ContentItem = host.AddContentItem(host.ScreenLayoutContentItem, "ParameterGroup", ContentItemKind.Group)
            host.SetContentItemView(parameterGroup, "Microsoft.LightSwitch.RichClient:ColumnsLayout")
            host.SetControlPropertyValue(parameterGroup, "Microsoft.LightSwitch.RichClient:RootControl", "VerticalAlignment", "Top")
            For Each param As ScreenPropertyBase In host.PrimaryDataSourceParameterProperties
                host.AddContentItem(parameterGroup, param.Name, param)
            Next
// Add parameters to the screen.
            ContentItem parameterGroup = host.AddContentItem(host.ScreenLayoutContentItem, "ParameterGroup", ContentItemKind.Group);
            host.SetContentItemView(parameterGroup, "Microsoft.LightSwitch.RichClient:ColumnsLayout");
            host.SetControlPropertyValue(parameterGroup, "Microsoft.LightSwitch.RichClient:RootControl", "VerticalAlignment", "Top");
            foreach (ScreenPropertyBase param in host.PrimaryDataSourceParameterProperties)
            {
                host.AddContentItem(parameterGroup, param.Name, param);
            }

Adding One Field from an Entity

You may have to identify and add a specific field from an entity to the screen. The following example illustrates how to find the definition of an entity and add a specific field from the selected item. Notice that the first code block duplicates code in an earlier example, "Display the Selected Item of a Collection."

'Find field called "Name"
            Dim nameProperty As IEntityPropertyDefinition = collectionDataType.Properties.Where(Function(p) p.Name.ToLower = "name").FirstOrDefault()
            If nameProperty IsNot Nothing Then
                'expression used to access collectionproperty.SelectedItem.Name
                Dim nameExpression As ChainExpression = host.CreateChainExpression(host.CreateMemberExpression(collectionProperty.Id))
                host.AppendMemberExpression(nameExpression, "SelectedItem")
                host.AppendMemberExpression(nameExpression, nameProperty.Name)
                Dim namePropertyControl As ContentItem = host.AddContentItem(host.ScreenLayoutContentItem,
                                                                             host.MakeUniqueLegalNameForContentItem("Name"),
                                                                             ContentItemKind.Value,
                                                                             nameExpression,
                                                                             nameProperty.PropertyType)
                host.SetControlPropertyValue(namePropertyControl, "Microsoft.LightSwitch.RichClient:RootControl", "VerticalAlignment", "Top")
            End If
// Find field called "Name".
            IEntityPropertyDefinition nameProperty = collectionDataType.Properties.Where(p => p.Name.ToLower() == "name").FirstOrDefault();
            if (nameProperty != null)
            {
                // Expression used to access collectionproperty.SelectedItem.Name
                ChainExpression nameExpression = host.CreateChainExpression(host.CreateMemberExpression(collectionProperty.Id));
                host.AppendMemberExpression(nameExpression, "SelectedItem");
                host.AppendMemberExpression(nameExpression, nameProperty.Name);
                ContentItem namePropertyControl = host.AddContentItem(host.ScreenLayoutContentItem,
                                                                             host.MakeUniqueLegalNameForContentItem("Name"),
                                                                             ContentItemKind.Value,
                                                                             nameExpression,
                                                                             nameProperty.PropertyType);
                host.SetControlPropertyValue(namePropertyControl, "Microsoft.LightSwitch.RichClient:RootControl", "VerticalAlignment", "Top");
            }

If your goal is to display all or most of the fields of an entity, a better option is to create a Detail node and use host.ExpandContentItem, and then modify the results if you have to.

Add Code to the Screen

You can use the host.AddScreenCodeBehind method to cause the template engine to add boilerplate code-behind to the screen as it is created. The developer can modify this code. You must supply code as a language-specific string. Therefore, you have to provide a code string for each language that you want to enable (currently, C# and Visual Basic are supported).The following example shows one way to do this, by using a dictionary that maps the coding language to a formatted string that contains the code for that language. First, a local property of type String is added to the screen, and then code is added behind the screen to set its value in the InitializeDataWorkspace method. The following example shows the dictionary that contains the code-behind for Visual Basic and C#.

Private Shared _codeTemplates As Dictionary(Of CodeLanguage, String) = New Dictionary(Of CodeLanguage, String)() From
        {
            {CodeLanguage.CSharp, _
                "" _
                + "{0}namespace {1}" _
                + "{0}{{" _
                + "{0}    public partial class {2}" _
                + "{0}    {{" _
                + "{0}" _
                + "{0}        partial void {2}_InitializeDataWorkspace(global::System.Collections.Generic.List<global::Microsoft.LightSwitch.IDataService> saveChangesTo)" _
                + "{0}        {{" _
                + "{0}            this.{3} = ""Hello World"";" _
                + "{0}        }}" _
                + "{0}" _
                + "{0}    }}" _
                + "{0}}}"
            }, _
            {CodeLanguage.VB, _
                "" _
                + "{0}Namespace {1}" _
                + "{0}" _
                + "{0}    Public Class {2}" _
                + "{0}" _
                + "{0}        Private Sub {2}_InitializeDataWorkspace(ByVal saveChangesTo As Global.System.Collections.Generic.List(Of Global.Microsoft.LightSwitch.IDataService))" _
                + "{0}            Me.{3} = ""Hello World""" _
                + "{0}        End Sub" _
                + "{0}" _
                + "{0}    End Class" _
                + "{0}" _
                + "{0}End Namespace" _
            }
        }
private static Dictionary<CodeLanguage, String> _codeTemplates = new Dictionary<CodeLanguage, String>()
        {
            {CodeLanguage.CSharp,
                ""
                + "{0}namespace {1}"
                + "{0}{{"
                + "{0}    public partial class {2}"
                + "{0}    {{"
                + "{0}"
                + "{0}        partial void {2}_InitializeDataWorkspace(global::System.Collections.Generic.List<global::Microsoft.LightSwitch.IDataService> saveChangesTo)"
                + "{0}        {{"
                + "{0}            this.{3} = \"Hello World\";"
                + "{0}        }}"
                + "{0}"
                + "{0}    }}"
                + "{0}}}"
            },
            {CodeLanguage.VB,
                ""
                + "{0}Namespace {1}"
                + "{0}"
                + "{0}    Public Class {2}"
                + "{0}"
                + "{0}        Private Sub {2}_InitializeDataWorkspace(ByVal saveChangesTo As Global.System.Collections.Generic.List(Of Global.Microsoft.LightSwitch.IDataService))"
                + "{0}            Me.{3} = \"Hello World\""
                + "{0}        End Sub"
                + "{0}"
                + "{0}    End Class"
                + "{0}"
                + "{0}End Namespace"
            }
        };

The following code must also be added to the Generate method:

' Code Generation
            Dim codeTemplate As String = ""
            If _codeTemplates.TryGetValue(host.ScreenCodeBehindLanguage, codeTemplate) Then
                host.AddScreenCodeBehind(String.Format(codeTemplate,
                                                       Environment.NewLine,
                                                       host.ScreenNamespace,
                                                       host.ScreenName,
                                                       screenProperty.Name))
            End If
// Code Generation
            string codeTemplate = "";
            if (_codeTemplates.TryGetValue(host.ScreenCodeBehindLanguage, out codeTemplate))
            {
                host.AddScreenCodeBehind(String.Format(codeTemplate,
                                                       Environment.NewLine,
                                                       host.ScreenNamespace,
                                                       host.ScreenName,
                                                       screenProperty.Name));
            }

Code Listing

The following is a complete code listing for a screen template named “TestTemplate” that includes all of the code in this topic.

Imports System
Imports System.Collections.Generic
Imports System.ComponentModel.Composition
Imports System.Text

Imports Microsoft.LightSwitch.Designers.ScreenTemplates.Model
Imports Microsoft.LightSwitch.Model.Storage
Imports Microsoft.LightSwitch.Model
Imports System.Management

Namespace ScreenTemplates

    Public Class TestTemplate
        Implements IScreenTemplate

#Region "IScreenTemplate Members"

        Public Sub Generate(host As IScreenTemplateHost) Implements IScreenTemplate.Generate
            Dim primaryDataControl As ContentItem = host.AddContentItem(host.ScreenLayoutContentItem, host.MakeUniqueLegalNameForContentItem("My Root Data"), host.PrimaryDataSourceProperty)
            host.SetContentItemView(primaryDataControl, "Microsoft.LightSwitch.RichClient:DataGrid")
            host.ExpandContentItem(primaryDataControl)

            host.SetControlPropertyValue(primaryDataControl, "Microsoft.LightSwitch.RichClient:RootControl", "VerticalAlignment", "Top")
            host.SetControlPropertyValue(primaryDataControl, "Microsoft.LightSwitch.RichClient:RootControl", "HeightSizingMode", "Auto")
            host.SetDisplayName(primaryDataControl, "Main Screen Data")

            DirectCast(host.PrimaryDataSourceProperty, ScreenCollectionProperty).DisablePaging = True

            'Get the data type of your property
            Dim collectionProperty As ScreenCollectionProperty = DirectCast(host.PrimaryDataSourceProperty, ScreenCollectionProperty)
            Dim collectionDataType As IEntityType = host.FindGlobalModelItem(Of ISequenceType)(collectionProperty.PropertyType).ElementType

            'Create an expression that represents accessing the selected item on your collection property
            Dim chain As ChainExpression = host.CreateChainExpression(host.CreateMemberExpression(collectionProperty.Id))
            host.AppendMemberExpression(chain, "SelectedItem")

            'Add a content item representing the selected item and set its view to a RowsLayout
            Dim detailControl As ContentItem = host.AddContentItem(host.ScreenLayoutContentItem, "ItemDetail", ContentItemKind.Details, chain, collectionDataType)
            host.SetContentItemView(detailControl, "Microsoft.LightSwitch.RichClient:RowsLayout")
            host.SetControlPropertyValue(detailControl, "Microsoft.LightSwitch.RichClient:RootControl", "VerticalAlignment", "Top")
            host.ExpandContentItem(detailControl)

            'Add parameters to the screen.
            Dim parameterGroup As ContentItem = host.AddContentItem(host.ScreenLayoutContentItem, "ParameterGroup", ContentItemKind.Group)
            host.SetContentItemView(parameterGroup, "Microsoft.LightSwitch.RichClient:ColumnsLayout")
            host.SetControlPropertyValue(parameterGroup, "Microsoft.LightSwitch.RichClient:RootControl", "VerticalAlignment", "Top")
            For Each param As ScreenPropertyBase In host.PrimaryDataSourceParameterProperties
                host.AddContentItem(parameterGroup, param.Name, param)
            Next

            'Find field called "Name".
            Dim nameProperty As IEntityPropertyDefinition = collectionDataType.Properties.Where(Function(p) p.Name.ToLower = "name").FirstOrDefault()
            If nameProperty IsNot Nothing Then
                'expression used to access collectionproperty.SelectedItem.Name
                Dim nameExpression As ChainExpression = host.CreateChainExpression(host.CreateMemberExpression(collectionProperty.Id))
                host.AppendMemberExpression(nameExpression, "SelectedItem")
                host.AppendMemberExpression(nameExpression, nameProperty.Name)
                Dim namePropertyControl As ContentItem = host.AddContentItem(host.ScreenLayoutContentItem,
                                                                             host.MakeUniqueLegalNameForContentItem("Name"),
                                                                             ContentItemKind.Value,
                                                                             nameExpression,
                                                                             nameProperty.PropertyType)
                host.SetControlPropertyValue(namePropertyControl, "Microsoft.LightSwitch.RichClient:RootControl", "VerticalAlignment", "Top")
            End If

            'Add a tabs group to the screen.
            Dim tabsGroup As ContentItem = host.AddContentItem(host.ScreenLayoutContentItem, "TabsGroup", ContentItemKind.Group)
            host.SetContentItemView(tabsGroup, "Microsoft.LightSwitch.RichClient:TabsLayout")

            For Each p As ScreenCollectionProperty In host.ChildCollectionProperties
                'Display each child collection as a grid
                Dim currentTab As ContentItem = host.AddContentItem(tabsGroup, host.MakeUniqueLegalNameForContentItem("Tab"), p)
                host.SetContentItemView(currentTab, "Microsoft.LightSwitch.RichClient:DataGrid")
                host.ExpandContentItem(currentTab)
            Next

            'Add a screen member.
            Dim screenProperty As ScreenProperty = host.AddScreenProperty("Microsoft.LightSwitch:String", "NewScreenProperty")

            'Code Generation
            Dim codeTemplate As String = ""
            If _codeTemplates.TryGetValue(host.ScreenCodeBehindLanguage, codeTemplate) Then
                host.AddScreenCodeBehind(String.Format(codeTemplate,
                                                       Environment.NewLine,
                                                       host.ScreenNamespace,
                                                       host.ScreenName,
                                                       screenProperty.Name))
            End If



        End Sub

        Private Shared _codeTemplates As Dictionary(Of CodeLanguage, String) = New Dictionary(Of CodeLanguage, String)() From
        {
            {CodeLanguage.CSharp, _
                "" _
                + "{0}namespace {1}" _
                + "{0}{{" _
                + "{0}    public partial class {2}" _
                + "{0}    {{" _
                + "{0}" _
                + "{0}        partial void {2}_InitializeDataWorkspace(global::System.Collections.Generic.List<global::Microsoft.LightSwitch.IDataService> saveChangesTo)" _
                + "{0}        {{" _
                + "{0}            this.{3} = ""Hello World"";" _
                + "{0}        }}" _
                + "{0}" _
                + "{0}    }}" _
                + "{0}}}"
            }, _
            {CodeLanguage.VB, _
                "" _
                + "{0}Namespace {1}" _
                + "{0}" _
                + "{0}    Public Class {2}" _
                + "{0}" _
                + "{0}        Private Sub {2}_InitializeDataWorkspace(ByVal saveChangesTo As Global.System.Collections.Generic.List(Of Global.Microsoft.LightSwitch.IDataService))" _
                + "{0}            Me.{3} = ""Hello World""" _
                + "{0}        End Sub" _
                + "{0}" _
                + "{0}    End Class" _
                + "{0}" _
                + "{0}End Namespace" _
            }
        }

        Public ReadOnly Property Description As String Implements IScreenTemplateMetadata.Description
            Get
                Return "Test Template Description"
            End Get
        End Property

        Public ReadOnly Property DisplayName As String Implements IScreenTemplateMetadata.DisplayName
            Get
                Return "Test Template"
            End Get
        End Property

        Public ReadOnly Property PreviewImage As Uri Implements IScreenTemplateMetadata.PreviewImage
            Get
                Return New Uri("/ScreenTemplateExtension.Design;component/Resources/ScreenTemplateImages/TestTemplateLarge.png", UriKind.Relative)
            End Get
        End Property

        Public ReadOnly Property RootDataSource As RootDataSourceType Implements IScreenTemplateMetadata.RootDataSource
            Get
                Return RootDataSourceType.Collection
            End Get
        End Property

        Public ReadOnly Property ScreenNameFormat As String Implements IScreenTemplateMetadata.ScreenNameFormat
            Get
                Return "{0}TestTemplate"
            End Get
        End Property

        Public ReadOnly Property SmallIcon As Uri Implements IScreenTemplateMetadata.SmallIcon
            Get
                Return New Uri("/ScreenTemplateExtension.Design;component/Resources/ScreenTemplateImages/TestTemplateSmall.png", UriKind.Relative)
            End Get
        End Property

        Public ReadOnly Property SupportsChildCollections As Boolean Implements IScreenTemplateMetadata.SupportsChildCollections
            Get
                Return True
            End Get
        End Property

        Public ReadOnly Property TemplateName As String Implements IScreenTemplateMetadata.TemplateName
            Get
                Return TestTemplate.TemplateId
            End Get
        End Property

#End Region

#Region "Constants"

        Friend Const TemplateId As String = "ScreenTemplateExtension:TestTemplate"

#End Region

    End Class

    <Export(GetType(IScreenTemplateFactory))>
    <Template(TestTemplate.TemplateId)>
    Friend Class TestTemplateFactory
        Implements IScreenTemplateFactory

#Region "IScreenTemplateFactory Members"

        Public Function CreateScreenTemplate() As IScreenTemplate Implements IScreenTemplateFactory.CreateScreenTemplate
            Return New TestTemplate()
        End Function

#End Region

    End Class

End Namespace
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Management;
using System.Text;

using Microsoft.LightSwitch.Designers.ScreenTemplates.Model;
using Microsoft.LightSwitch.Model;
using Microsoft.LightSwitch.Model.Storage;

namespace ScreenTemplateExtension.ScreenTemplates
{
    public class TestTemplate : IScreenTemplate
    {
        #region IScreenTemplate Members

        public void Generate(IScreenTemplateHost host)
        {
            ContentItem primaryDataControl = host.AddContentItem(host.ScreenLayoutContentItem, host.MakeUniqueLegalNameForContentItem("My Root Data"), host.PrimaryDataSourceProperty);
            host.SetContentItemView(primaryDataControl, "Microsoft.LightSwitch: .RichClient DataGrid");
            host.ExpandContentItem(primaryDataControl);

            host.SetControlPropertyValue(primaryDataControl, "Microsoft.LightSwitch.RichClient:RootControl", "VerticalAlignment", "Top");
            host.SetControlPropertyValue(primaryDataControl, "Microsoft.LightSwitch.RichClient:RootControl", "HeightSizingMode", "Auto");
            host.SetDisplayName(primaryDataControl, "Main Screen Data");

            ((ScreenCollectionProperty)host.PrimaryDataSourceProperty).DisablePaging = true;

            // Get the data type of your property.
            ScreenCollectionProperty collectionProperty = (ScreenCollectionProperty)(host.PrimaryDataSourceProperty);
            IEntityType collectionDataType = host.FindGlobalModelItem<ISequenceType>(collectionProperty.PropertyType).ElementType as IEntityType;

            // Create an expression that represents accessing the selected item on your collection property.
            ChainExpression chain = host.CreateChainExpression(host.CreateMemberExpression(collectionProperty.Id));
            host.AppendMemberExpression(chain, "SelectedItem");

            // Add a content item representing the selected item and set its view to a RowsLayout.
            ContentItem detailControl = host.AddContentItem(host.ScreenLayoutContentItem, "ItemDetail", ContentItemKind.Details, chain, collectionDataType);
            host.SetContentItemView(detailControl, "Microsoft.LightSwitch.RichClient:RowsLayout");
            host.SetControlPropertyValue(detailControl, "Microsoft.LightSwitch.RichClient:RootControl", "VerticalAlignment", "Top");
            host.ExpandContentItem(detailControl);

            // Add parameters to the screen.
            ContentItem parameterGroup = host.AddContentItem(host.ScreenLayoutContentItem, "ParameterGroup", ContentItemKind.Group);
            host.SetContentItemView(parameterGroup, "Microsoft.LightSwitch.RichClient:ColumnsLayout");
            host.SetControlPropertyValue(parameterGroup, "Microsoft.LightSwitch.RichClient:RootControl", "VerticalAlignment", "Top");
            foreach (ScreenPropertyBase param in host.PrimaryDataSourceParameterProperties)
            {
                host.AddContentItem(parameterGroup, param.Name, param);
            }

            // Find field called "Name".
            IEntityPropertyDefinition nameProperty = collectionDataType.Properties.Where(p => p.Name.ToLower() == "name").FirstOrDefault();
            if (nameProperty != null)
            {
                // Expression used to access collectionproperty.SelectedItem.Name
                ChainExpression nameExpression = host.CreateChainExpression(host.CreateMemberExpression(collectionProperty.Id));
                host.AppendMemberExpression(nameExpression, "SelectedItem");
                host.AppendMemberExpression(nameExpression, nameProperty.Name);
                ContentItem namePropertyControl = host.AddContentItem(host.ScreenLayoutContentItem,
                                                                             host.MakeUniqueLegalNameForContentItem("Name"),
                                                                             ContentItemKind.Value,
                                                                             nameExpression,
                                                                             nameProperty.PropertyType);
                host.SetControlPropertyValue(namePropertyControl, "Microsoft.LightSwitch.RichClient:RootControl", "VerticalAlignment", "Top");
            }

            // Add a tabs group to the screen.
            ContentItem tabsGroup = host.AddContentItem(host.ScreenLayoutContentItem, "TabsGroup", ContentItemKind.Group);
            host.SetContentItemView(tabsGroup, "Microsoft.LightSwitch.RichClient:TabsLayout");

            foreach (ScreenCollectionProperty p in host.ChildCollectionProperties)
            {
                // Display each child collection as a grid.
                ContentItem currentTab = host.AddContentItem(tabsGroup, host.MakeUniqueLegalNameForContentItem("Tab"), p);
                host.SetContentItemView(currentTab, "Microsoft.LightSwitch.RichClient:DataGrid");
                host.ExpandContentItem(currentTab);
            }

            // Add a screen member.
            ScreenProperty screenProperty = host.AddScreenProperty("Microsoft.LightSwitch:String", "NewScreenProperty") as ScreenProperty;

            // Code Generation
            string codeTemplate = "";
            if (_codeTemplates.TryGetValue(host.ScreenCodeBehindLanguage, out codeTemplate))
            {
                host.AddScreenCodeBehind(String.Format(codeTemplate,
                                                       Environment.NewLine,
                                                       host.ScreenNamespace,
                                                       host.ScreenName,
                                                       screenProperty.Name));
            }
        }

        private static Dictionary<CodeLanguage, String> _codeTemplates = new Dictionary<CodeLanguage, String>()
        {
            {CodeLanguage.CSharp,
                ""
                + "{0}namespace {1}"
                + "{0}{{"
                + "{0}    public partial class {2}"
                + "{0}    {{"
                + "{0}"
                + "{0}        partial void {2}_InitializeDataWorkspace(global::System.Collections.Generic.List<global::Microsoft.LightSwitch.IDataService> saveChangesTo)"
                + "{0}        {{"
                + "{0}            this.{3} = \"Hello World\";"
                + "{0}        }}"
                + "{0}"
                + "{0}    }}"
                + "{0}}}"
            },
            {CodeLanguage.VB,
                ""
                + "{0}Namespace {1}"
                + "{0}"
                + "{0}    Public Class {2}"
                + "{0}"
                + "{0}        Private Sub {2}_InitializeDataWorkspace(ByVal saveChangesTo As Global.System.Collections.Generic.List(Of Global.Microsoft.LightSwitch.IDataService))"
                + "{0}            Me.{3} = \"Hello World\""
                + "{0}        End Sub"
                + "{0}"
                + "{0}    End Class"
                + "{0}"
                + "{0}End Namespace"
            }
        };

        public string Description
        {
            get { return "TestTemplate Description"; }
        }

        public string DisplayName
        {
            get { return "Test Template"; }
        }

        public Uri PreviewImage
        {
            get { return new Uri("/ScreenTemplateExtension.Design;component/Resources/ScreenTemplateImages/TestTemplateLarge.png", UriKind.Relative); }
        }

        public RootDataSourceType RootDataSource
        {
            get { return RootDataSourceType.Collection; }
        }

        public string ScreenNameFormat
        {
            get { return "{0}TestTemplate"; }
        }

        public Uri SmallIcon
        {
            get { return new Uri("/ScreenTemplateExtension.Design;component/Resources/ScreenTemplateImages/TestTemplateSmall.png", UriKind.Relative); }
        }

        public bool SupportsChildCollections
        {
            get { return true; }
        }

        public string TemplateName
        {
            get { return TestTemplate.TemplateId; }
        }

        #endregion

        #region Constants

        internal const string TemplateId = "ScreenTemplateExtension:TestTemplate";

        #endregion
    }

    [Export(typeof(IScreenTemplateFactory))]
    [Template(TestTemplate.TemplateId)]
    internal class TestTemplateFactory : IScreenTemplateFactory
    {
        #region IScreenTemplateFactory Members

        IScreenTemplate IScreenTemplateFactory.CreateScreenTemplate()
        {
            return new TestTemplate();
        }

        #endregion
    }
}

See Also

Tasks

How to: Debug or Test a LightSwitch Extension

How to: Create a LightSwitch Extension Project

Concepts

LightSwitch Control ViewIDs

Defining, Overriding, and Using LightSwitch Control Properties

LightSwitch Extensibility Toolkit for Visual Studio 2013