Visual Studio LightSwitch Custom Control Extensions Development

[Infragistics] Mihail Mateev / Tuesday, October 5, 2010

Visual Studio LightSwitch proposes a flexible extensibility mechanism to use custom data sources, controls or themes.

This article is related with custom LightSwitch control extension – the powerful approach to make your Silverlight components available in Visual Studio LightSwitch extensions.

The LightSwitch framework leverages the capabilities of the Managed Extensibility Framework (MEF) to expose (and discover) extensibility points. By taking advantage of these extensibility points, developers can create their own components to be consumed from LightSwitch applications. LightSwitch takes advantage of Visual Studio's extensibility mechanisms by allowing LightSwitch extensions to be distributed and installed using VSIX installers.

The article contains a walk through how to create a LightSwitch extension, using XamNumericSlider component from Infragistics Silverlight UI Controls suite.

Requirements to build an application:

Software:

Steps to reproduce a sample:

  • Create a Silverlight 4 Application, named XamNumericSliderControl.Client.
    This project contains the implementation of the XamNumericSliderControl
    and provides the IControlFactory and IResourceProvider implementation and exports
    to make the control available in LightSwitch.
  • Create a Silverlight 4 Host Application, used to host and test a LightSwitch control extension.
  • Create a Silverlight 4 Library - XamNumericSliderControl.Common.
    This project defines the control as a LightSwitch enabled extension by using metadata files associated to the control. This metadata is provided by exporting an IModuleDefinitionLoader implementation.
  • Create a CLR4 project, named XamNumericSliderControl.Design.
    (Provides support for the Visual Studio Screen designer. It contains the icons and images that will be used to represent the control. These images are provided by exporting an IResourceProvider implementation.)
  • Create a LightSwicth specific packaging project XamNumericSliderControl.LsPkg
    (This project references the assemblies from all aforementioned projects. As well as all assemblies that are necessary for the package to work.)
  • Create a VSIX Project: XamNumericSliderControl.Vsix
    This project creates a Vsix package containing the LsPkg package and provides a consumption mechanism for it as a Visual Studio extension.
  • Install the Extension and enable it in a project InfraOrders (based on the article “Creating a Visual Studio LightSwitch Custom Silverlight Control (Using Infragistics Components)”.
  • Add in the project InfraOrders OrderDetails ListView screen and use XamNumericSliderControl to display the Quantity value.
  • Run the application 

Create a Silverlight 4 Application

  • Create an empty solution, named XamNumericSliderControlExtension.
  • Add a new Silverlight 4 Application project , named XamNumericSliderControl.Client.
  • Create a folders, named Controls , ControlImages and Resources:
  • In the Controls folder add an user control, named XamNumericSlider.xaml.
  • Add four dependency properties: Value, MinValue, MaxValue and NumberOfTickMarks:
   1: #region MaxValue (DependencyProperty)
   2:  
   3: /// <summary>
   4: /// A description of the property.
   5: /// </summary>
   6: public double MaxValue
   7: {
   8:     get { return (double)GetValue(MaxValueProperty); }
   9:     set { SetValue(MaxValueProperty, value); }
  10: }
  11: public static readonly DependencyProperty MaxValueProperty =
  12:     DependencyProperty.Register("MaxValue", typeof(double), typeof(XamNumericSlider),
  13:       new PropertyMetadata(100.0));
  14:  
  15: #endregion
  16:  
  17:  
  18: #region MinValue (DependencyProperty)
  19:  
  20: /// <summary>
  21: /// A description of the property.
  22: /// </summary>
  23: public double MinValue
  24: {
  25:     get { return (double)GetValue(MinValueProperty); }
  26:     set { SetValue(MinValueProperty, value); }
  27: }
  28: public static readonly DependencyProperty MinValueProperty =
  29:     DependencyProperty.Register("MinValue", typeof(double), typeof(XamNumericSlider),
  30:       new PropertyMetadata(0.0));
  31:  
  32: #endregion
  33:  
  34:  
  35: #region NumberOfTickMarks (DependencyProperty)
  36:  
  37: /// <summary>
  38: /// A description of the property.
  39: /// </summary>
  40: public int NumberOfTickMarks
  41: {
  42:     get { return (int)GetValue(NumberOfTickMarksProperty); }
  43:     set { SetValue(NumberOfTickMarksProperty, value); }
  44: }
  45: public static readonly DependencyProperty NumberOfTickMarksProperty =
  46:     DependencyProperty.Register("NumberOfTickMarks", typeof(int), typeof(XamNumericSlider),
  47:       new PropertyMetadata(10, new PropertyChangedCallback(OnNumberOfTickMarksChanged)));
  48:  
  49:  
  50: private static void OnNumberOfTickMarksChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
  51: {
  52:     ((XamNumericSlider)d).OnNumberOfTickMarksChanged(e);
  53: }
  54:  
  55: protected virtual void OnNumberOfTickMarksChanged(DependencyPropertyChangedEventArgs e)
  56: {
  57:     int x = (int) e.NewValue;
  58:     this.xamNumericSliderControl.TickMarks[0].NumberOfTickMarks = x;
  59: }
  60:  
  61: #endregion
  62:  
  63: #region Value (DependencyProperty)
  64:  
  65: /// <summary>
  66: /// A description of the property.
  67: /// </summary>
  68: public double Value
  69: {
  70:     get { return (double)GetValue(ValueProperty); }
  71:     set { SetValue(ValueProperty, value); }
  72: }
  73: public static readonly DependencyProperty ValueProperty =
  74:     DependencyProperty.Register("Value", typeof(double), typeof(XamNumericSlider),
  75:       new PropertyMetadata(0.0));
  76:  
  77: #endregion //Value
  • Add in the Xaml file add an instance of the Infragistics XamNumericSlider, bound to the properties in the UserControl
   1: <UserControl x:Name="RootPanel" x:Class="XamNumericSliderControl.Client.XamNumericSlider"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
   5:     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
   6:     xmlns:ls="clr-namespace:Microsoft.LightSwitch.Presentation.Framework;assembly=Microsoft.LightSwitch.Client"
   7:     xmlns:ig="http://schemas.infragistics.com/xaml"
   8:     mc:Ignorable="d" HorizontalContentAlignment="Stretch">
   9:  
  10:     <ls:AttachedLabelItemPresenter LabelStyleId="AttachedLabelStyle" HorizontalAlignment="Stretch">
  11:         <ls:ContentSizingControl HorizontalAlignment="Stretch" 
  12:             ContentSizingMode="{Binding Properties[ContentSizingMode]}"
  13:             ContentSize="{Binding Properties[ContentSize]}">
  14:             <ig:XamNumericSlider HorizontalAlignment="Stretch" Width="{Binding ElementName=RootPanel, Path=Width}" 
  15:                                 Height="{Binding ElementName=RootPanel, Path=Height}" 
  16:                                  Name="xamNumericSliderControl" VerticalAlignment="Top" 
  17:                                  MinValue="{Binding ElementName=RootPanel, Path=MinValue}" 
  18:                                  MaxValue="{Binding ElementName=RootPanel, Path=MaxValue}"
  19:                                  Value="{Binding ElementName=RootPanel, Path=Value}">
  20:                 <ig:XamNumericSlider.Thumb>
  21:                     <ig:XamSliderNumericThumb ToolTipVisibility="Visible" IsDragEnabled="False"/>
  22:                 </ig:XamNumericSlider.Thumb>
  23:                 <ig:XamNumericSlider.TickMarks>
  24:                     <ig:SliderTickMarks UseFrequency="False"
  25:                                         NumberOfTickMarks="{Binding ElementName=RootPanel, Path=NumberOfTickMarks}"/>
  26:                 </ig:XamNumericSlider.TickMarks>
  27:             </ig:XamNumericSlider>
  28:         </ls:ContentSizingControl>
  29:     </ls:AttachedLabelItemPresenter>
  30: </UserControl>
Files in the ControlImages and Resources folder will be implemented in the later stage, when we have a XamNumericSliderControl.Design
assembly.
 
  • Make a XamNumericSliderControl.Client.XamNumericSlider a root visual for this application:
 
  • Change in the App.xaml.cs Application_Startup event handler to have the code below:
   1: private void Application_Startup(object sender, StartupEventArgs e)
   2: {
   3:     this.RootVisual = new XamNumericSliderControl.Client.XamNumericSlider();
   4: }
 
Create a Silverlight 4 Host Application, used to host and test a LightSwitch control extension
 
  • Make a reference to XamWebSliderControl.Client assembly and add in instance of a XamWebSliderControl in the MainPage.xaml in the host application:
   1: <StackPanel x:Name="LayoutRoot" Background="White">
   2:      <TextBlock>This Silverlight page hosts the XamNumericSlider Control for testing the control in the usual Silverlight environment.</TextBlock>
   3:      <TextBlock>The Lab will guide you on how to create a LightSwitch Extension to use this control.</TextBlock>
   4:      <TextBlock FontWeight="Bold">XamNumericSlider Control:</TextBlock>
   5:      <Controls:XamNumericSlider Value="20" MaxValue="100" NumberOfTickMarks="9" Width="300"></Controls:XamNumericSlider>
   6:  </StackPanel> 

This application could be used to test the LightSwitch control extension in a Silverlight host to be sure that the extension
works properly.

 

Create a Silverlight 4 Library - XamNumericSliderControl.Common.

  • Add the XamNumericSliderControlModule class.

The XamNumericSliderModule class will define the Module and Control’s name. Use the following code to do this:

   1: namespace XamNumericSliderControl.Client
   2: {
   3:     public class XamNumericSliderControlModule
   4:     {
   5:         public const string Name = "XamNumericSliderControl";
   6:         private const string ModulePrefix = Name + ":";
   7:  
   8:         public class XamNumericSliderControl
   9:         {
  10:             private const string Name = "XamNumericSliderControl";
  11:             public const string GlobalName = ModulePrefix + Name;
  12:         }
  13:     }
  14: }
  • Create a Metadata folder inside the XamNumericSlider.Common project. In this folder you will place all the metadata files that describe the LightSwitch extension. To do this, right click the XamNumericSlider.Common project and select Add | New Folder. Name the folder Metadata.
  • Create a Resources folder inside the XamNumericSlider.Common project. In this folder you will place a resource file. To do this, right click the XamNumericSlider.Common project and select Add | New Folder. Name the folder Resources.
  • Inside the Resources folder add a new resource file named XamNumericSliderControlResources.resx.
  • Inside the Metadata folder create a new class named XamNumericSliderControlModuleLoader.  
  • Add the following references to the XamNumericSliderControl.Common project
    System.ComponentModel.Composition
    Microsoft.LightSwitch. By default LightSwitch installs this assembly at C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\LightSwitch\1.0\Client\
  • The XamNumericSliderControlModuleLoader class will load the module definition files by implementing the LightSwitch the IModuleDefinitionLoader interface. Copy the following code to make the XamNumericSliderControlModuleLoader class implement the IModuleDefinitionLoader interface:
   1: [DebuggerNonUserCodeAttribute(), Export(typeof(IModuleDefinitionLoader)), ModuleDefinitionLoader(XamNumericSliderControlModule.Name)]
   2: public class XamNumericSliderControlModuleLoader : IModuleDefinitionLoader
   3: {
   4:  
   5:     #region Member Variables
   6:  
   7:     private static string[] ModelFragments = { "XamNumericSliderControlModule.lsml", "XamNumericSliderControlPresentation.lsml" };
   8:     private static string ResourceNamespace = typeof(XamNumericSliderControlModuleLoader).Namespace;
   9:     private const string ResourcePathFormat = "{0}.{1}";
  10:  
  11:     #endregion //Member Variables
  12:  
  13:     #region IModuleDefinitionLoader
  14:  
  15:     public ResourceManager GetModelResourceManager()
  16:     {
  17:  
  18:         return Resources.XamNumericSliderControlResources.ResourceManager;
  19:     }
  20:  
  21:     public IEnumerable<Stream> LoadModelFragments()
  22:     {
  23:  
  24:         Assembly assem = Assembly.GetExecutingAssembly();
  25:         List<Stream> fragmentList = new List<Stream>();
  26:  
  27:         foreach (string fragment in ModelFragments)
  28:         {
  29:             string fragmentPath = string.Format(ResourcePathFormat, ResourceNamespace, fragment);
  30:  
  31:             Stream fragmentStream = assem.GetManifestResourceStream(fragmentPath);
  32:             Debug.Assert(fragmentStream != null, "Could not obtain fragment stream.", "Looking for {0}", fragmentPath);
  33:  
  34:             fragmentList.Add(fragmentStream);
  35:         }
  36:  
  37:         return fragmentList;
  38:     }
  39:  
  40:     #endregion //IModuleDefinitionLoader
  41: }

 

LightSwitch uses MEF to compose the different extension parts, and includes some LightSwitch specific attributes to help this purpose. To export the class as an IModuleDefinitionLoader use the following attributes to decorate the class:

[DebuggerNonUserCodeAttribute(), Export(typeof(IModuleDefinitionLoader)), ModuleDefinitionLoader(XamNumericSliderControlModule.Name)]

  • Add the XamNumericSliderControlModule.lsml metadata file to the Metadata folder. This XML file will define the module's name. To do this, add a new file to the Metadata folder with the lsml extension. You can use the XML File template specifying the name and extension

In the Properties window, set the Build Action of the BingMapControlModule.lsml file to Embedded Resource.

   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <ModelFragment
   3:   xmlns="http://schemas.microsoft.com/LightSwitch/2010/xaml/model"
   4:   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   5:  
   6:   <Module Name="XamNumericSliderControl" />
   7:  
   8: </ModelFragment>
  • Add the XamNumericSliderControlPresentation.lsml metadata file. This file will contain the LightSwitch control definitions. The procedure for this is similar to step to create XamNumericSliderControlModule.lsml file.
   1: <?xml version="1.0" encoding="utf-8" ?>
   2: <ModelFragment
   3:   xmlns="http://schemas.microsoft.com/LightSwitch/2010/xaml/model"
   4:   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   5:  
   6:   <Control
   7:     Name="XamNumericSliderControl"
   8:     BaseControl="RootValueControl"
   9:     SupportedContentItemKind="Value"
  10:     DesignerImageResource="XamNumericSliderImages::XamNumericSliderControl" >
  11:     <Control.Attributes>
  12:       <DisplayName Value="$(XamNumericSliderControl_DisplayName)" />
  13:     </Control.Attributes>
  14:     <Control.SupportedDataTypes>
  15:       <SupportedDataType DataType="Decimal"/>
  16:       <SupportedDataType DataType="Int16"/>
  17:       <SupportedDataType DataType="Int32"/>
  18:       <SupportedDataType DataType="Int64"/>
  19:       <SupportedDataType DataType="Double"/>
  20:     </Control.SupportedDataTypes>
  21:  
  22:     <!-- Property overrides -->
  23:     <Control.PropertyOverrides>
  24:  
  25:       <!-- ContentSizingMode override -->
  26:       <ControlPropertyOverride
  27:         Property="Microsoft.LightSwitch:RootControl/Properties[ContentSizingMode]"
  28:         EditorVisibility="NotDisplayed">
  29:         <ControlPropertyOverride.DefaultValueSource>
  30:           <ScreenExpressionTree>
  31:             <ChainExpression>
  32:               <ConstantExpression ResultType="Microsoft.LightSwitch:String" Value="Text" />
  33:             </ChainExpression>
  34:           </ScreenExpressionTree>
  35:         </ControlPropertyOverride.DefaultValueSource>
  36:       </ControlPropertyOverride>
  37:  
  38:       <!-- ContentSize override -->
  39:       <ControlPropertyOverride
  40:         Property="Microsoft.LightSwitch:RootControl/Properties[ContentSize]"
  41:         EditorVisibility="PropertySheet">
  42:         <ControlPropertyOverride.DefaultValueSource>
  43:           <ScreenExpressionTree>
  44:             <ChainExpression>
  45:               <ConstantExpression ResultType="Microsoft.LightSwitch:String" Value="Auto" />
  46:             </ChainExpression>
  47:           </ScreenExpressionTree>
  48:         </ControlPropertyOverride.DefaultValueSource>
  49:       </ControlPropertyOverride>
  50:  
  51:     </Control.PropertyOverrides>
  52:  
  53:     <!-- XamNumericSliderControl Properties -->
  54:     <Control.Properties>
  55:  
  56:       <!-- XamNumericSliderControl MinValue Property -->
  57:       <ControlProperty Name="MinValue"
  58:         PropertyType="Microsoft.LightSwitch:Double"
  59:         IsReadOnly="False"
  60:         CategoryName="XamNumericSlider Properties"
  61:         EditorVisibility="PropertySheet">      
  62:         <ControlProperty.Attributes>
  63:           <DisplayName Value="$(XamNumericSliderControl_MinValue_DisplayName)"/>
  64:           <Description Value="$(XamNumericSliderControl_MinValue_Description)"/>
  65:         </ControlProperty.Attributes>
  66:       </ControlProperty>
  67:  
  68:       <!-- XamNumericSliderControl MaxValue Property -->
  69:       <ControlProperty Name="MaxValue"
  70:         PropertyType="Microsoft.LightSwitch:Double"
  71:         IsReadOnly="False"
  72:         CategoryName="XamNumericSlider Properties"
  73:         EditorVisibility="PropertySheet">
  74:         <ControlProperty.Attributes>
  75:           <DisplayName Value="$(XamNumericSliderControl_MaxValue_DisplayName)"/>
  76:           <Description Value="$(XamNumericSliderControl_MaxValue_Description)"/>
  77:         </ControlProperty.Attributes>
  78:       </ControlProperty>
  79:  
  80:       <!--NumberOfTickMarks-->
  81:       <ControlProperty Name="NumberOfTickMarks"
  82:         PropertyType="Microsoft.LightSwitch:Int32"
  83:         IsReadOnly="False"
  84:         CategoryName="XamNumericSlider Properties"
  85:         EditorVisibility="PropertySheet">
  86:         <ControlProperty.Attributes>
  87:           <DisplayName Value="$(XamNumericSliderControl_NumberOfTickMarks_DisplayName)"/>
  88:           <Description Value="$(XamNumericSliderControl_NumberOfTickMarks_Description)"/>
  89:         </ControlProperty.Attributes>
  90:       </ControlProperty>
  91:  
  92:     </Control.Properties>
  93:  
  94:   </Control>
  95: </ModelFragment>

This file is the most important for design mode settings for LightSwitch custom control extension. It describes witch additional properties to display in design mode ,
size of the control content and and specifies the data types that can be bound to the control.

 

  • Open the XamNumericSliderControlResources.resx file inside the Resources folder.
    Define the following resource entries and values for design mode support:

Add necessary classes to the Client project
In this task you will work on the project named XamNumericSliderControl.Client. In this project you will implement the functionality for the custom control using the metadata exposed through the XamNumericSliderControl.Common project.

  • Add a reference to the following assemblies in the XamNumericSliderControl.Common project:
    Microsoft.LightSwitch.dll. By default this assembly is located at C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\LightSwitch\1.0\Client\.
    Microsoft.LightSwitch.Client.dll. By default this assembly is located in the same directory as Microsoft.LightSwitch.dll.
  • In the Solution Explorer, right-click the XamNumericSliderControl.Client project and select the option to add an existing item. The Add Existing Item dialog appears.
  • Select the BingMapControlModule.cs file located under the XamNumericSliderControl.Common folder and add it as a link.
  • Add images 16x16 and 32x32 (XamNumericSliderControl16.png, XamNumericSliderControl32.png) in the ControlImages folder.
  • In he Resources folder add XamNumericSliderImageProvider.cs and XamNumericSliderImages.xaml files.

XamNumericSliderImages.xaml

   1: <ResourceDictionary
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   4:     <BitmapImage x:Key="XamNumericSliderControl16" UriSource="/XamNumericSliderControl.Design;component/ControlImages/XamNumericSliderControl16.png"/>
   5:     <BitmapImage x:Key="XamNumericSliderControl32" UriSource="/XamNumericSliderControl.Design;component/ControlImages/XamNumericSliderControl32.png"/>
   6:  
   7: </ResourceDictionary>

 

XamNumericSliderImageProvider.cs

   1: [Export(typeof(IResourceProvider)), ResourceProvider("XamNumericSliderImages")]
   2: public class XamNumericSliderImageProvider : IResourceProvider
   3: {
   4:  
   5:     private static ResourceDictionary Resources;
   6:     static XamNumericSliderImageProvider()
   7:     {
   8:         Uri resourceUri = new Uri("/XamNumericSliderControl.Client;component/Resources/XamNumericSliderImages.xaml", UriKind.Relative);
   9:         Resources = new ResourceDictionary();
  10:         Resources.Source = resourceUri;
  11:     }
  12:  
  13:     public object GetResource(string resourceId, CultureInfo cultureInfo)
  14:     {
  15:         //throw new NotImplementedException();
  16:  
  17:         if (!(XamNumericSliderImageProvider.Resources.Contains(resourceId)))
  18:         {
  19:             return null;
  20:         }
  21:         else
  22:         {
  23:             return XamNumericSliderImageProvider.Resources[resourceId];
  24:         }
  25:     }
  26: }

 

  • In the Controls folder add DataTemplates.xaml file:
   1: <ResourceDictionary
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   4:     xmlns:s="clr-namespace:XamNumericSliderControl.Client;assembly=XamNumericSliderControl.Client">
   5:     <DataTemplate x:Key="XamNumericSliderTemplate">
   6:         <s:XamNumericSlider Value="{Binding Details.Value, Mode=TwoWay}"            
   7:             MinValue="{Binding Properties[MinValue], Mode=TwoWay}" 
   8:             MaxValue="{Binding Properties[MaxValue],  Mode=TwoWay}" 
   9:             NumberOfTickMarks="{Binding Properties[NumberOfTickMarks], Mode=TwoWay}" 
  10:             ></s:XamNumericSlider>
  11:     </DataTemplate>
  12: </ResourceDictionary>

 

Build Actions for each of these files could be find in the demo project.

  • In the XamNumericSliderControl.Client project add also XamNumericSliderControlFactory.cs file.
   1: [Export(typeof(IControlFactory)), Export(typeof(IControlFactory))]
   2: [ControlFactory(XamNumericSliderControlModule.XamNumericSliderControl.GlobalName)]
   3: public class XamNumericSliderControlFactory : IControlFactory
   4: {
   5:     #region Member Variables
   6:     private DataTemplate _dataTemplate;
   7:     private static ResourceDictionary Dictionary;
   8:     #endregion //Member Variables
   9:  
  10:     #region Constructors
  11:  
  12:     static XamNumericSliderControlFactory()
  13:     {
  14:         // Get resource
  15:         Uri resourceUri = GetResourceUri();
  16:         StreamResourceInfo streamInfo = System.Windows.Application.GetResourceStream(resourceUri);
  17:         Debug.Assert(streamInfo != null, "ResourceDictionary load failed.", "Stream not found: {0}", resourceUri.ToString());
  18:  
  19:         if (streamInfo != null)
  20:         {
  21:             // Read resource contents
  22:             string contents = string.Empty;
  23:             using (var reader = new StreamReader(streamInfo.Stream))
  24:             {
  25:                 contents = reader.ReadToEnd();
  26:             }
  27:  
  28:             // Ensure contents is not empty
  29:             Debug.Assert(!(string.IsNullOrEmpty(contents)), "ResourceDictionary load failed.", "Resource was empty: {0}", resourceUri.ToString());
  30:  
  31:             // Load the contents as resource dictionary
  32:             XamNumericSliderControlFactory.Dictionary = (ResourceDictionary)XamlReader.Load(contents);
  33:             Debug.Assert(XamNumericSliderControlFactory.Dictionary != null, "ResourceDictionary load failed.", "Resource wasn't ResourceDictionary: {0}", resourceUri.ToString());
  34:         }
  35:     }
  36:  
  37:     public XamNumericSliderControlFactory(string templateKey)
  38:     {
  39:         _dataTemplate = XamNumericSliderControlFactory.GetDataTemplate(templateKey);
  40:     }
  41:  
  42:     public XamNumericSliderControlFactory()
  43:         : this("XamNumericSliderTemplate")
  44:     //INSTANT C# TODO TASK: C# does not have an equivalent to VB's 'MyClass' keyword
  45:     //ORIGINAL LINE: MyClass.New("BingMapTemplate")
  46:     {
  47:     }
  48:  
  49:     #endregion //Constructors
  50:  
  51:     #region IControlFactory
  52:  
  53:     #region DataTemplate
  54:     public DataTemplate DataTemplate
  55:     {
  56:         //get { throw new NotImplementedException(); }
  57:         get
  58:         {
  59:             return _dataTemplate;
  60:         }
  61:     }
  62:     #endregion //DataTemplate
  63:  
  64:     #region GetDisplayModeDataTemplate
  65:     public DataTemplate GetDisplayModeDataTemplate(IContentItem contentItem)
  66:     {
  67:         //throw new NotImplementedException();
  68:         return null;
  69:     }
  70:     #endregion //GetDisplayModeDataTemplate
  71:  
  72:     #endregion //IControlFactory
  73:  
  74:     private static DataTemplate GetDataTemplate(string templateKey)
  75:     {
  76:         Debug.Assert(XamNumericSliderControlFactory.Dictionary.Contains(templateKey), "DataTemplate not found.", "Looking for resource key '{0}'", templateKey);
  77:  
  78:         return XamNumericSliderControlFactory.Dictionary[templateKey] as DataTemplate;
  79:     }
  80:  
  81:     private static Uri GetResourceUri()
  82:     {
  83:         Assembly assembly = Assembly.GetExecutingAssembly() as Assembly;
  84:         AssemblyName thisAssemblyName = new AssemblyName(assembly.FullName);
  85:  
  86:         return new Uri(thisAssemblyName.Name + ";component/Controls/DataTemplates.xaml", UriKind.Relative);
  87:     }
  88: }

 

Create a CLR4 project, named XamNumericSliderControl.Design.

The Design project is a CLR Class Library project that will provide the design time support for the control in Visual Studio Screen Designer, such as images.

  • Add a new Windows Class Library project to the XamNumericSliderControl solution named XamNumericSliderControl.Design.
  • Add a new folder named ControlImages to the XamNumericSliderControl.Design project. This folder will contain the images used to show the control in the Screen Designer.
  • Add a new folder named Resources to the XamNumericSliderControl.Design project. This folder will contain the assets necessary to load the control images.
  • Place the XamNumericSliderControl16.png and XamNumericSliderControl.32.png images inside the ControlImages folder.
    Set the Build Action for these two image files as Resource. To do this, select each file and in the Properties windows set the Build Action property to Resource.
  • Add a XamNumericSliderImages.xaml file to the Resources folder.
   1: <ResourceDictionary
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   4:     <BitmapImage x:Key="XamNumericSliderControl16" UriSource="/XamNumericSliderControl.Design;component/ControlImages/XamNumericSliderControl16.png"/>
   5:     <BitmapImage x:Key="XamNumericSliderControl32" UriSource="/XamNumericSliderControl.Design;component/ControlImages/XamNumericSliderControl32.png"/>
   6:  
   7: </ResourceDictionary>
  • Add the following references to the XamNumericSliderControl.Design project:
    System.ComponentModel.Composition
    System.Xaml
    Microsoft.LightSwitch.

By default LightSwitch installs this assembly at C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\LightSwitch\1.0\Client\

  • Add the XamNumericSliderImageProvider class
   1: [Export(typeof(IResourceProvider)), ResourceProvider("XamNumericSliderImages")]
   2: public class XamNumericSliderImageProvider : IResourceProvider
   3: {
   4:  
   5:     private static ResourceDictionary Resources;
   6:     static XamNumericSliderImageProvider()
   7:     {
   8:         Uri resourceUri = new Uri("/XamNumericSliderControl.Client;component/Resources/XamNumericSliderImages.xaml", UriKind.Relative);
   9:         Resources = new ResourceDictionary();
  10:         Resources.Source = resourceUri;
  11:     }
  12:  
  13:     public object GetResource(string resourceId, CultureInfo cultureInfo)
  14:     {
  15:         //throw new NotImplementedException();
  16:  
  17:         if (!(XamNumericSliderImageProvider.Resources.Contains(resourceId)))
  18:         {
  19:             return null;
  20:         }
  21:         else
  22:         {
  23:             return XamNumericSliderImageProvider.Resources[resourceId];
  24:         }
  25:     }
  26: }

 

Create a LightSwicth specific packaging project XamNumericSliderControl.LsPkg

You need to add the XamNumericSliderControl.LsPkg project that generates a LightSwitch package, an .lspkg file that contains all the resources created in previous steps.

  • Add the XamNumericSliderControl.LsPkg class library project to the XamNumericSliderControl solution.
  • Change the content of the XamNumericSliderControl.LsPkg.csproj project file to add a references as a links:
   1: <?xml version="1.0" encoding="utf-8"?>
   2: <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   3:   <!-- This project creates a LSPKG package for the XamNumericSliderControl extension -->
   4:   <PropertyGroup>
   5:     <ProjectGuid>{224E0EAF-CCF6-4197-8FE3-EB08124B194C}</ProjectGuid>
   6:     <OutputPath>..\XamNumericSliderControl.Vsix\</OutputPath>
   7:     <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
   8:     <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
   9:     <LightSwitchVersion>v1.0</LightSwitchVersion>
  10:   </PropertyGroup>
  11:   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
  12:     <PlatformTarget>x86</PlatformTarget>
  13:     <DebugSymbols>true</DebugSymbols>
  14:     <DebugType>full</DebugType>
  15:     <Optimize>false</Optimize>
  16:     <ProjectPath>bin\Debug\</ProjectPath>
  17:     <DefineConstants>DEBUG;TRACE</DefineConstants>
  18:     <ErrorReport>prompt</ErrorReport>
  19:     <WarningLevel>4</WarningLevel>
  20:   </PropertyGroup>
  21:   <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
  22:     <PlatformTarget>x86</PlatformTarget>
  23:     <DebugType>pdbonly</DebugType>
  24:     <Optimize>true</Optimize>
  25:     <ProjectPath>bin\Release\</ProjectPath>
  26:     <DefineConstants>TRACE</DefineConstants>
  27:     <ErrorReport>prompt</ErrorReport>
  28:     <WarningLevel>4</WarningLevel>
  29:   </PropertyGroup>
  30:   <PropertyGroup>
  31:     <CreateLSPKG>true</CreateLSPKG>
  32:     <LSPKGPackageName>LightSwitch XamNumericSlider Control</LSPKGPackageName>
  33:     <PackageOutputFilename>$(OutputPath)\XamNumericSliderControl.LsPkg</PackageOutputFilename>
  34:     <Author>DPE</Author>
  35:     <PackageVersion>1.0</PackageVersion>
  36:     <PackageID>XamNumericSliderControl</PackageID>
  37:   </PropertyGroup>
  38:   <PropertyGroup>
  39:     <AssemblyName>XamNumericSliderControl.LsPkg</AssemblyName>
  40:   </PropertyGroup>
  41:   <ItemGroup>
  42:     <ClientGeneratedReference Include="..\XamNumericSliderControl.Client\Bin\$(Configuration)\XamNumericSliderControl.Client.dll" />
  43:     <ClientGeneratedReference Include="..\Lib\InfragisticsSL4.v10.2.dll" />
  44:     <ClientGeneratedReference Include="..\Lib\InfragisticsSL4.Controls.Editors.XamSlider.v10.2.dll" />
  45:     <ClientGeneratedReference Include="..\XamNumericSliderControl.Common\Bin\$(Configuration)\XamNumericSliderControl.Common.dll" />
  46:     <IDEReference Include="..\XamNumericSliderControl.Common\Bin\$(Configuration)\XamNumericSliderControl.Common.dll" />
  47:     <IDEReference Include="..\XamNumericSliderControl.Design\Bin\$(Configuration)\XamNumericSliderControl.Design.dll" />    
  48:     <ServerGeneratedReference Include="..\XamNumericSliderControl.Design\Bin\$(Configuration)\XamNumericSliderControl.Design.dll" />
  49:   </ItemGroup>
  50:   <ItemGroup>
  51:     <Folder Include="My Project\" />
  52:   </ItemGroup>
  53:   <ItemGroup>
  54:     <ProjectReference Include="..\XamNumericSliderControl.Client\XamNumericSliderControl.Client.csproj">
  55:       <Project>{AE03E032-7583-4410-9824-D1BE1718DA08}</Project>
  56:       <Name>XamNumericSliderControl.Client</Name>
  57:     </ProjectReference>
  58:     <ProjectReference Include="..\XamNumericSliderControl.Common\XamNumericSliderControl.Common.csproj">
  59:       <Project>{0E41E89D-7478-4BCB-818E-79AEB4650818}</Project>
  60:       <Name>XamNumericSliderControl.Common</Name>
  61:     </ProjectReference>
  62:   </ItemGroup>
  63:   <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
  64:   <!-- Override these targets because we're not building an assembly in this project file like in the traditional sense -->
  65:   <Target Name="Compile" Condition="'$(BuildingInsideVisualStudio)' != 'true'" />
  66:   <Target Name="CopyFilesToOutputDirectory" Condition="'$(BuildingInsideVisualStudio)' != 'true'" />
  67:   <Import Project="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\LightSwitch\$(LightSwitchVersion)\Microsoft.LightSwitch.SDK.targets" />
  68: </Project>

Set a specific output path for the generated  LsPkg : ..\XamNumericSliderControl.Vsix\

Create a VSIX Project: XamNumericSliderControl.Vsix

In Visual Studio, add a new VSIX project named XamNumericSliderControl.Vsix. To do this, you can use the VSIX Project template.

In the VSIX Manifest Editor, complete the Author field with the author you want to appear for the installer.

 

  • Build the XamNumericSliderControlsolution.
  • Add the XamNumericSliderControl.lsPkg to the VSIX project. To do this, perform the following steps:
    In Content section of the VSIX Manifest Editor, click Add Content.
    In the Select a source section, check the File option.
    In the Choose File dialog, select the XamNumericSliderControl.LsPkg file located under LsPkg build output folder.
  • Rebuild the XamNumericSliderControlsolution. When the XamNumericSliderControl.Vsix project is built, it generates the XamNumericSliderControl.Vsix installer under the output folder.

Install the Extension and enable it in a project InfraOrders

  • Look at the installed extensions Tools->Extensions Manager in Visual Studio 2010

There is no XamNumericSliderControl extension

  • Run the Vsix installer

Look at the installed extensions Tools->Extensions Manager in Visual Studio 2010 (there must be XamNumericSliderControl)

Add in the project InfraOrders OrderDetails ListView screen and use XamNumericSliderControl to display the Quantity value.

  • Add a new List and Detail Screen named OrderListListDetail using data from OrderList
  • In the details column change the control, used for Quantity to XamNumericSliderControl
  • In the property sheet set MaxValue=100, NumberOfTickMarks=9

Check that OrderListListDetail screen is added to the screen navigation.

 Run the application 

  • Select the OrderListListDetail screen

Quantity value is represented via XamNumericSliderControl LightSwitch extension.

Summary:

This example demonstrates the advantages of LightSwitch custom control extensions.
It is possible in the same way to create LightSwitch extensions based on Silverlight components and add functionalities to your LightSwitch  application.
Article is based on the Visual Studio LightSwitch Beta 1. Probably in the future creating of LightSwitch extensions will be easier and faster, including project
templates for LsPkg projects and some specific items.