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

  1. On the menu bar in Visual Studio, choose File, New, Project.

  2. 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.

  3. 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.

  4. Choose the OK button to create a solution that contains the seven projects that are required for the extension.

To choose an extension type

  1. In Solution Explorer, choose the MyStackPanelExtension.Lspkg file.

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

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

  4. In the Name field, enter MyStackPanel as the name for your extension. This name will appear in the LightSwitch screen designer.

  5. 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

  1. 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.

  2. In the Open With dialog box, choose Paint and then choose the OK button.

  3. In Paint, change the image, for example, change the color or add a shape, and then save the file and return to Visual Studio.

  4. Choose the MyStackPanel.png file, and then on the menu bar, choose Edit, Copy.

  5. 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

  1. 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.

  2. In the Open With dialog box, choose XML (Text) Editor, and then choose the OK button.

  3. Change the SupportedContentItemKind element to SupportedContentItemKind="Group".

    This tells LightSwitch that it is a group control.

  4. 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.

  5. Change the DisplayName element as follows: <DisplayName Value="$(MyStackPanel_DisplayName)" />.

    The $(ResourceName) notation tells LightSwitch to retrieve the value from a resource file.

  6. 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.

  7. Delete the Control.SupportedDataTypes block. Because a group control cannot directly display data, this block is unnecessary.

  8. 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

  1. In Solution Explorer, expand the Resources node in the MyStackPanelExtension.Common, and then open the ModuleResources.resx file.

  2. 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

  1. In Solution Explorer, open the MyStackPanel.xaml file in the MyStackPanelExtension.Client project.

  2. 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

  1. In Solution Explorer, open the MyStackPanel.lsml file in the Controls folder of the MyStackPanelExtension.Common project.

  2. 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>
    
  3. Expand the Resources node in MyStackPanelExtension.Common, and then open the ModuleResources.resx file.

  4. 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

  1. In Solution Explorer, select the Controls node in the MyStackPanelExtension.Client project.

  2. On the menu bar, choose Project, Add Class.

  3. In the Add New Item dialog box, name the class DoubleToThicknessConverter, and then choose the Add button.

  4. 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

  1. In Solution Explorer, open the MyStackPanel.xaml file in the MyStackPanelExtension.Client project.

  2. Add the following namespace mapping.

    xmlns:controls="clr-namespace:MyStackPanelExtension.Presentation.Controls;assembly=MyStackPanelExtension.Client"
    
  3. 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>
    
  4. 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

  1. In Solution Explorer, choose the BusinessTypeExtension.Vsix project.

  2. On the menu bar, choose Project, BusinessTypeExtension.Vsix Properties.

  3. On the Debug tab, under Start Action, choose Start external program.

  4. 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.

  5. 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

  1. On the menu bar, choose Debug, Start Debugging. An experimental instance of Visual Studio opens.

  2. In the experimental instance, on the menu bar, choose File, New, Project.

  3. 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.

  4. In the Name field, enter MyStackPanelTest, and then choose the OK button to create a test project.

  5. On the menu bar, choose Project, MyStackPanelTest Properties.

  6. In the project designer, on the Extensions tab, select the MyStackPanelExtension check box.

  7. 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.

  8. 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

LightSwitch Extensibility Toolkit for Visual Studio 2013