Walkthrough: Creating a Stack Panel Control Extension
This walkthrough demonstrates how to create a stack panel control extension for LightSwitch. By using a stack panel, you can stack elements in an assigned direction. Examples of some stack panel controls are included in the LightSwitch screen designer, for example, the Vertical Layout and Horizontal Layout group controls.
Prerequisites
Visual Studio 2013 Professional
Visual Studio 2013 SDK
LightSwitch Extensibility Toolkit for Visual Studio 2013
Create a Control Extension Project
The first step is to create a project and add a LightSwitch Control template.
To create an extension project
On the menu bar in Visual Studio, choose File, New, Project.
In the New Project dialog box, expand the Visual Basic or Visual C# node, expand the LightSwitch node, choose the Extensibility node, and then choose the LightSwitch Extension Library template.
In the Name field, enter MyStackPanelExtension as the name for your extension library. This name will appear on the Extensions tab of the LightSwitch Application Designer.
Choose the OK button to create a solution that contains the seven projects that are required for the extension.
To choose an extension type
In Solution Explorer, choose the MyStackPanelExtension.Lspkg file.
On the menu bar, choose Project, Add New Item.
In the Add New Item dialog box, choose LightSwitch Control.
In the Name field, enter MyStackPanel as the name for your extension. This name will appear in the LightSwitch screen designer.
Choose the OK button. Files will be added to several projects in your solution.
Update the Control Icon
Two image files named MyStackPanel.png were added to your solution, one in the ControlImages folder of the MyStackPanelExtension.Client.Design project and the other in the ControlImages folder of the MyStackPanelExtension.Design project. The image in the file is used as an icon. You can replace the default image with one that uniquely identifies your control.
To modify the icon image
In Solution Explorer, on the shortcut menu for the MyStackPanel.png file in the ControlImages folder of the MyStackPanelExtension.Client.Design project, choose Open With.
In the Open With dialog box, choose Paint and then choose the OK button.
In Paint, change the image, for example, change the color or add a shape, and then save the file and return to Visual Studio.
Choose the MyStackPanel.png file, and then on the menu bar, choose Edit, Copy.
Choose the ControlImages folder of the MyStackPanelExtension.Design project, and then on the menu bar choose Edit, Paste. In the message that asks whether you want to replace the file, choose the Yes button.
Update the Control Definition in the LightSwitch Metadata File
Metadata that defines the control is contained in the .lsml file in the MyStackPanelExtension.Common project. For your smart layout control, you can replace some of the default values with values that are appropriate for your control, for example, the control type and the display name. You can also add placeholders for child items and define the behavior of the AttachedLabelPosition settings.
To update the control metadata
In Solution Explorer, open the shortcut menu for the MyStackPanel.lsml file in the Controls folder of the MyStackPanelExtension.Common project and choose Open With.
In the Open With dialog box, choose XML (Text) Editor, and then choose the OK button.
Change the SupportedContentItemKind element to SupportedContentItemKind="Group".
This tells LightSwitch that it is a group control.
After the SupportedContentItemKind element, insert this element: AttachedLabelSupport="DisplayedByControl".
This tells LightSwitch that the group control will handle the AttachedLabelPosition property for any child controls.
Change the DisplayName element as follows: <DisplayName Value="$(MyStackPanel_DisplayName)" />.
The $(ResourceName) notation tells LightSwitch to retrieve the value from a resource file.
Insert the following code after the Control.Attributes block.
<!-- Override AttachedLabelPosition so it can be shown on the property sheet. --> <Control.PropertyOverrides> <ControlPropertyOverride Property=":RootControl/Properties[AttachedLabelPosition]" EditorVisibility="PropertySheet"> </ControlPropertyOverride> </Control.PropertyOverrides>
This tells LightSwitch to display the AttachedLabelPosition property in the property sheet so that a developer can specify a default value for the child controls.
Delete the Control.SupportedDataTypes block. Because a group control cannot directly display data, this block is unnecessary.
The complete code for the MyStackPanel.lsml file should now resemble the following example.
<ModelFragment xmlns="https://schemas.microsoft.com/LightSwitch/2010/xaml/model" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"> <Control Name="MyStackPanel" SupportedContentItemKind="Group" AttachedLabelSupport="DisplayedByControl" DesignerImageResource="MyStackPanelExtension.MyStackPanel::ControlImage"> <Control.Attributes> <DisplayName Value="$(MyStackPanel_DisplayName)" /> </Control.Attributes> <!-- Override AttachedLabelPosition so it can be shown on the property sheet. --> Add the following xaml code <ControlPropertyOverride Property=":RootControl/Properties[AttachedLabelPosition]" EditorVisibility="PropertySheet"> </ControlPropertyOverride> </Control.PropertyOverrides> </Control> </ModelFragment>
Add a Resource String
The ModuleResources.resx file in the MyStackPanelExtension.Common project contains resources that are used by the control. You can add a string resource for the display name that you specified in the MyStackPanel.lsml file.
To add a resource string
In Solution Explorer, expand the Resources node in the MyStackPanelExtension.Common, and then open the ModuleResources.resx file.
Add the following value to the ModuleResources.resx file.
Name
Value
Comment
MyStackPanel_DisplayName
My Stack Panel Control
The display name for the control; to be displayed in the screen designer.
Update the Control Xaml File
The MyStackPanel.xaml file in the MyStackPanelExtension.Client project contains the markup language that defines the Silverlight control. The default control is a TextBox; change it to a container that can display child controls.
To update the xaml
In Solution Explorer, open the MyStackPanel.xaml file in the MyStackPanelExtension.Client project.
Replace the contents of the file with the following xaml code.
<UserControl x:Class="MyStackPanelExtension.Presentation.Controls.MyStackPanel" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:framework ="clr-namespace:Microsoft.LightSwitch.Presentation.Framework;assembly=Microsoft.LightSwitch.Client" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"> <!-- An ItemsControl is used here to create ContentItemPresenter for all child items in the LightSwitch content tree. --> <ItemsControl ItemsSource="{Binding ChildItems}" > <!-- ItemsPanel enables the use of a stack panel to arrange all child items. Different group controls typically use different layout panels here. --> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Vertical" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <!-- ItemTemplate enables the mapping of a content item to a Silverlight control. Use a ContentItemPresenter here; bind its ContentItem to the ContentItem in the LightSwitch screen content tree. --> <ItemsControl.ItemTemplate> <DataTemplate> <framework:ContentItemPresenter ContentItem="{Binding}" /> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </UserControl>
An ItemsControl is used to map child items of the group node to Silverlight controls, and host them in a stack panel. The DataContext of a LightSwitch control is always an IContentItem object, and the ContentItemPresenter is used to display a ContentItem as a Silverlight control.
Define a Margin Property for Child Items in the Screen Content Tree
At this point, you could test the control, but the appearance might not be what you expect. Any child controls that you added to the control would appear without spacing between them. You can fix this by defining a Margin property.
By using the Margin property, a developer can specify the amount of space between controls at design time. You could define a fixed amount of space, but exposing the property gives developers more flexibility.
To define a margin property
In Solution Explorer, open the MyStackPanel.lsml file in the Controls folder of the MyStackPanelExtension.Common project.
Add the following xaml code after the Control.PropertyOverrides block.
<!-- Define New Control Properties --> <Control.Properties> <!-- Define a Margin property for all immediate children of the stack panel. It must be an attachable property, just like a Grid in Silverlight adds the Grid.Row property to its children. --> <ControlProperty Name="Margin" PropertyType=":Double" IsAttachable="True" AttachedPropertyAvailability="ImmediateChildren" EditorVisibility="PropertySheet" > <ControlProperty.Attributes> <!-- Reference to the localized name in ModuleResources.resx --> <DisplayName Value="$(Margin_DisplayName)" /> <!-- Reference to the localized description string in ModuleResources.resx --> <Description Value="$(Margin_Description)" /> </ControlProperty.Attributes> <!-- Define the default value of Margin to 0. --> <ControlProperty.DefaultValueSource> <ScreenExpressionTree> <ConstantExpression ResultType=":Double" Value="0"/> </ScreenExpressionTree> </ControlProperty.DefaultValueSource> </ControlProperty> </Control.Properties>
Expand the Resources node in MyStackPanelExtension.Common, and then open the ModuleResources.resx file.
Add the following value to the ModuleResources.resx file.
Name
Value
Description
Margin_DisplayName
Margin
Property name
Margin_Description
The space between child controls.
Property description that is used in the screen designer.
Create a Value Converter to Convert the Control Property Value to a Silverlight Value
Silverlight controls use the Thickness type to represent margins. Therefore, you have to create a converter to convert the Double property value of Margin to the Silverlight Thickness type.
To create a value converter
In Solution Explorer, select the Controls node in the MyStackPanelExtension.Client project.
On the menu bar, choose Project, Add Class.
In the Add New Item dialog box, name the class DoubleToThicknessConverter, and then choose the Add button.
Add the following code to the class module.
Imports System.Windows Imports System.Windows.Data Namespace MyStackPanelExtension.Presentation.Controls ' A value converter to convert a Double value defined in the control property to a Thickness value used in the Silverlight control. Public Class DoubleToThicknessConverter Implements IValueConverter Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.Convert Return New Thickness(CDbl(value)) End Function Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack Throw New NotSupportedException() End Function End Class End Namespace
using System; using System.Windows; using System.Windows.Data; namespace MyStackPanelExtension.Presentation.Controls { /// <summary> /// A value converter to convert double value defined in the control property to a Thickness value used in the Silverlight control. /// </summary> public class DoubleToThicknessConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return new Thickness((double)value); } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotSupportedException(); } } }
Add the Margin Property to the Control
The final step is to bind the Margin property of the LightSwitch control to the Silverlight implementation.
To add the margin
In Solution Explorer, open the MyStackPanel.xaml file in the MyStackPanelExtension.Client project.
Add the following namespace mapping.
xmlns:controls="clr-namespace:MyStackPanelExtension.Presentation.Controls;assembly=MyStackPanelExtension.Client"
Add the converter as a static resource in the control.
<UserControl.Resources> <!-- Define a converter to convert a LightSwitch control property to the value that is used in Silverlight controls. --> <controls:DoubleToThicknessConverter x:Key="DoubleToThicknessConverter" /> </UserControl.Resources>
Add the Margin property to the ContentPresenterItem element.
<framework:ContentItemPresenter ContentItem="{Binding}" Margin="{Binding Path=Properties[MyStackPanelExtension:MyStackPanel/Margin], Converter={StaticResource DoubleToThicknessConverter}}" />
The complete code for the MyStackPanel.xaml file should now resemble the following example.
<UserControl x:Class="MyStackPanelExtension.Presentation.Controls.MyStackPanel" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:framework ="clr-namespace:Microsoft.LightSwitch.Presentation.Framework;assembly=Microsoft.LightSwitch.Client" xmlns:controls="clr-namespace:MyStackPanelExtension.Presentation.Controls;assembly=MyStackPanelExtension.Client" xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"> <UserControl.Resources> <!-- Define a converter to convert a LightSwitch control property to the value used in Silverlight controls. --> <controls:DoubleToThicknessConverter x:Key="DoubleToThicknessConverter" /> </UserControl.Resources> <!-- An ItemsControl is used here to create ContentItemPresenter for all child items in the LightSwitch content tree. --> <ItemsControl ItemsSource="{Binding ChildItems}" > <!-- ItemsPanel enables the use of a stack panel to arrange all child items. Different group controls typically use different layout panels here. --> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <StackPanel Orientation="Vertical" /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <!-- ItemTemplate enables the mapping of a content item to a Silverlight control. Use a ContentItemPresenter here; bind its ContentItem to the ContentItem in the LightSwitch screen content tree. --> <ItemsControl.ItemTemplate> <DataTemplate> <framework:ContentItemPresenter ContentItem="{Binding}" Margin="{Binding Path=Properties[MyStackPanelExtension:MyStackPanel/Margin], Converter={StaticResource DoubleToThicknessConverter}}" /> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </UserControl>
Test the Stack Panel Control
The smart layout control is now complete. You can test it in an experimental instance of Visual Studio. If you have not already tested another LightSwitch extensibility project, you have to enable the experimental instance first.
To enable an experimental instance
In Solution Explorer, choose the BusinessTypeExtension.Vsix project.
On the menu bar, choose Project, BusinessTypeExtension.Vsix Properties.
On the Debug tab, under Start Action, choose Start external program.
Enter the path of the Visual Studio executable, devenv.exe.
By default on a 32-bit system, the path is C:\Program Files\Microsoft Visual Studio 12.0\Common7\IDE\devenv.exe; on a 64-bit system, it is C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\devenv.exe.
In the Command line arguments field, enter /rootsuffix Exp.
Note
All subsequent LightSwitch extensibility projects will also use this setting, by default.
To test the stack panel control
On the menu bar, choose Debug, Start Debugging. An experimental instance of Visual Studio opens.
In the experimental instance, on the menu bar, choose File, New, Project.
In the New Project dialog box, expand the Visual Basic or Visual C# node, choose the LightSwitch node, and then choose the LightSwitch Desktop Application template.
In the Name field, enter MyStackPanelTest, and then choose the OK button to create a test project.
On the menu bar, choose Project, MyStackPanelTest Properties.
In the project designer, on the Extensions tab, select the MyStackPanelExtension check box.
Create a basic LightSwitch application that has a List and Details screen, and then in the screen designer, change the control for the Rows Layout to My Stack Panel.
Select a child item under My Stack Panel. Notice that the Margin property appears in the Properties window.
On the menu bar, choose Debug, Start Debugging. Observe the behavior of the My Stack Panel control in the application.
See Also
Tasks
How to: Create a LightSwitch Control
Concepts
Defining, Overriding, and Using LightSwitch Control Properties