C H A P T E R  10

Creating and Using Extensions

LightSwitch gives you a simpler and faster way to create high-quality business applications for the desktop and the cloud. When the team created LightSwitch, they also laid the groundwork for enterprise developers, IT departments, community contributors, ISV’s (Independent Software Vendors), and even individual developers to extend it in various ways.

Out-of-the-box, LightSwitch is already a fairly compelling RAD (Rapid Application Development) experience, but there’s room to add significant value to the product, by creating extensions. In essence, the team has tried to give you what you need, while allowing you to add what you want.

LightSwitch provides the following extension points: themes, shells, screen templates, controls, business types, and data sources. Each of these extension points involves different LightSwitch tiers, as shown in Figure 10-1.

Images

Figure 10-1. LightSwitch Extension Points

Understanding the Need for Extensions

Extensions can enable users to increase their productivity by providing extra functionality beyond LightSwitch’s current capabilities. The six types of LightSwitch extensions fall into three broad categories:

  • Enhanced Look and Feel
    • Theme extensions
    • Shell extensions
  • Advanced Data Entry
    • Screen template extensions
    • Control extensions
    • Business Type extensions
  • External Data Access
    • Data Source extensions

Enhanced Look and Feel

When you create a LightSwitch application, it looks the same as any other LightSwitch application. You can spot a standard LightSwitch application immediately. Microsoft has taken a pretty conservative approach with the program’s default theme. Its internal name is BlueGlossy, even though it’s far from, well, “glossy.”

Actually, there are two built-in themes, but one of them isn’t available for you to choose unless you happen to know it exists (which you now do) and you specifically make it available. It’s a high-contrast theme that uses selected Windows system colors, and it’s automatically used if your Windows theme is set to a high contrast theme. Its internal name is simply Black.

By the time you finish reading this chapter, you should be able to create your own theme. Later in the chapter, after we’ve showed you how to create a theme extension, we’ll also show you how to activate this “hidden” theme (of course, it isn’t really hidden) as one of the selectable theme choices.

So, if you’d like to ensure that your LightSwitch application doesn’t look generic, you can add a bit of sophistication and polish to it by creating:

  • A theme extension that uses your chosen color scheme (rather than someone else’s idea of what looks good)
  • A shell extension that might move various screen elements to a different place or change the look of them

A theme is the basically the look of the application (the colors, the fonts, the control styles), while a shell can be thought of as the feel of it (the position and functionality of, say, the menu system for example, whether screens are exposed as a series of tabs or in some other way). By using both a theme extension and a shell extension together, you can completely customize the look and feel of a LightSwitch application, compared to the default appearance.

Advanced Data Entry

Screen templates enable you to save time by not having to create the same type of screen from scratch, over and over. For example, for every application that you write, you will probably want some type of home page for it. Later in this chapter, we’ll show you how you could create a standard home page by creating a screen template extension. The new template will then be displayed as another choice in the Add New Screen Wizard.

Chapter 9 showed you how to create custom controls. Using a custom control allows you to enter data in a way that isn’t available in LightSwitch out-of-the-box. Creating a control extension allows you package custom controls for use in multiple projects, or to share them with the community, or even sell them.

Business type extensions enable you to create new data types based on the existing data types that LightSwitch already understands. When you choose Money as the type for a property, you’re really storing a Decimal value. When you choose Phone Number, you’re really dealing with a String value. Each business type extends the data type that it’s based on, adding custom formatting and perhaps extra validation.

External Data Access

In Chapter 7, you learned how to create a custom RIA service, which enables you to access external data that LightSwitch doesn’t natively know how to talk to. The downside is that you’d have to include that code in any application that needs access to that particular type of data.

If you need to access a particular type of external data in several LightSwitch applications, you can encapsulate the code in a data source extension, and by doing that make it available to those applications, without having to duplicate the code in each one.

Finding Extensions

While extensions can be developed in-house, they can also be created by third-party vendors, ISVs, and even members of the LightSwitch community. Some extensions are available at no charge, some are offered as trial versions (free to try, but must be purchased after a predetermined amount of time for them to continue to provide full functionality), and others are paid products that you’ll have to buy before you can use them.

Installing a trial edition of an extension, if one’s available, can be a good way to test it out first, to see whether it does what you need before you actually buy it. Colleagues and friends can share free extensions and trial extensions via email by simply sending the setup file. You can go to the Visual Studio Gallery web site or use Visual Studio’s Extension Manager to search for, download, and then install any of the three extension types (free, trial, or paid).

Visual Studio Gallery

The Visual Studio Gallery web site (http://visualstudiogallery.msdn.microsoft.com/site/search) is a kind of marketplace for all types of Visual Studio extensions, including LightSwitch extensions. Being a website, you can access it with your favorite browser. On the site, you can either browse through the myriad of available extensions (there are thousands of them!), or use search criteria to narrow your search to the particular type of extension that you’re interested in.

Figure 10-2 shows several free LightSwitch controls, made available to the LightSwitch community by one of the book’s authors.

Images

Figure 10-2. Visual Studio Gallery search

Visual Studio Extension Manager

The Extension Manager that’s built into Visual Studio (see Figure 10-3) provides a more integrated way to access the gallery contents, without the need for a browser. You’ll notice, though, that there are no criteria selections, as there are on the web site, apart from a text search. This is also the place (in fact, it’s the only place) to select any extension that you’ve previously installed and either disable it or uninstall it altogether.

Images

Figure 10-3. Visual Studio Extension Manager

Accessing the Extension Manager

There are two methods that you can use to access the Extension Manager.

Method 1 – LightSwitch Properties Screen

You can access the Extension Manager via the Extensions tab (see Figure 10-4) of the LightSwitch project’s properties:

  1. Double-click the LightSwitch project’s Properties folder in Solution Explorer.
  2. Click the Extensions tab.
  3. Click the Browse for More Extensions Online link to browse the Visual Studio Gallery web site.
  4. The Extension Manager window opens. By default, it shows the installed extensions, as you saw earlier in Figure 10-3.
Images

Figure 10-4. Extensions tab’s Browse for More Extensions Online link

Method 2 – Visual Studio Tools Menu

You can also access the Extension Manager via the Tools menu in Visual Studio (see Figure 10-5):

  1. Click the Tools menu.
  2. Click the Extension Manager option.
  3. The Extension Manager window opens. Again, by default it shows the installed extensions.
Images

Figure 10-5. Accessing the Extension Manager through the Tools menu

Using the Extension Manager

After the Extension Manager is open, as shown in Figure 10-6:

  1. Click the Online Gallery option.
  2. A list of all available online extensions is displayed in the middle pane (not just LightSwitch extensions).
  3. Type lightswitch in the search box.
  4. A list of extensions that contain lightswitch is now displayed.
  5. You can sort the list of extensions by:
    • Highest Ranked
    • Most Downloads
    • Name: Ascending
    • Name: Descending
    • Author: Ascending
    • Author: Descending
Images

Figure 10-6. Using the Extension Manager to search for extensions.

LightSwitch Community Extensions

Several LightSwitch community members have made extensions available. These extensions fill gaps that exist in the current version or offer new functionality not provided by the team. In both cases, it’s possible that the team just didn’t have the time to include everything that they would have liked to include in the first version of the product.

Two of the first contributors, and the contents of their contributions, are listed below. Other community members have since followed their example.

Spursoft Solutions

Spursoft LightSwitch Extensions is the most polished of the currently available third-party commercial extensions. They started life humbly as a small suite of free controls, which has now grown into quite a professional offering. Although now a paid product, it’s available at a very modest price.

  • http://www.spursoft.com/Extensions.htm
  • Menu-Driven Shell (menu can be docked by the user, at runtime, in 1 of 4 positions)
  • LightSwitch Themes
    • Twilight Blue
    • Twilight Green
    • Hill Country (inspired by the colors in the Hill Country area in Texas)
  • Drop Down List (simple list allowing for up and down arrow keys to navigate and select the items from the list)
  • Horizontal and Vertical Splitters (allows the designer to split the UI into user resizable panes either vertically or horizontally)
  • SQL Server Reporting Server Viewer (web browser based control, allowing for the display of SQL Server Reporting Services Reports)
  • Enhanced Selection DataGrid (allows for the multiple selection of congruent or incongruent rows)
  • Web Browser Control (allows displaying web content)
Luminous Software

Several extensions are currently available for free from Luminous Software, (although though donations are welcome to help cover development costs).

  • http://lightswitchcentral.com.au/Extensions/LuminousSoftware.aspx
  • Luminous Themes (a collection of two LightSwitch themes):
    • The first community-based themes to be released
    • Luminous Dark Purple
    • Luminous Dark Blue
  • Luminous Controls (a collection of two LightSwitch controls:
    • TextBlock (allowing static text to be added to a screen, with no code)
    • GroupLayout (allowing controls to be grouped, with a title, a themed background, and a border, all with no code)
  • Luminous LightSwitch Types (a collection of four LightSwitch business types):
    • Percent type (stores value as decimal, displays it as a percent)
    • ISBN type (validates ISBN-10, and ISBN-13 numbers)
    • Link type (clicking on the URL launches a web browser)
    • Password type (stores a string, displays a masked value)
  • Luminous LightSwitch Commands (a collection of four global ribbon commands that appear on each screen automatically)
    • Close And Save (closes the current screen, saving any changes)
    • Close And Cancel (closes the current screen, cancelling any changes)
    • Log Off (logs off the current user, but only in web applications)
    • Exit (exits the application completely)

Third-Party Vendors

Several third-party vendors claim to support LightSwitch. As of this writing, only some have developed native LightSwitch controls, while others provide tutorials on how to use their Silverlight offerings as LightSwitch custom controls. We suspect that they may be waiting for version 2 of LightSwitch before making a full commitment.

Infragistics
  • http://lightswitchcentral.net.au/Extensions/ThirdParty.aspx#infragistics
  • NetAdvantage for Visual Studio LightSwitch
    • PAID product
    • Editor controls (mask, numeric)
    • Map controls (geo-spatial, and value-based)
    • Gauge controls (radial, linear, segmented display)
    • Chart controls (area series, column series, line series, spline series, spline area series, step area series, step line series, pie, bullet)
    • Themes (IG, Metro, Office 2010 Blue, Orange)
    • Shell (Outlook/TileView navigation)
    • Slider controls (DateTime, Numeric, DateTime range, Numeric range)
  • NetAdvantage for Visual Studio LightSwitch Light
    • FREE product
    • Editor Controls (mask, numeric)
    • Themes (Metro, Office 2010 Theme)
First Floor Software
  • http://lightswitchcentral.net.au/Extensions/ThirdParty.aspx#firstfloor
  • Document Toolkit for LightSwitch (adds document-viewing capabilities to your LightSwitch application)
    • PAID product
    • XPS documents
    • PDF documents (At the time of this writing, PDF support is experimental and correct rendering is not guaranteed.)
    • Microsoft Office documents such as Word, Excel, and PowerPoint (This requires Microsoft Office 2007 and the Save As XPS add-in or Microsoft Office 2010. In addition, LightSwitch must be deployed as a desktop application.)
ComponentOne
  • http://lightswitchcentral.net.au/Extensions/ThirdParty.aspx#componentone
  • OLAP for LightSwitch (provides a pivoting data screen to get in-depth BI (Business Intelligence) functionality)
    • PAID product
    • Simply select a specific data entity or query for the component to use
    • Create a new screen using the accompanying screen template
    • The control is an example of both a custom control extension and a screen template extension being packaged together to make the control more usable for the LightSwitch developer.
RSSBus
DevExpress
  • http://lightswitchcentral.net.au/Extensions/ThirdParty.aspx#devexpress
  • DXEditors for LightSwitch
    • FREE license (for a limited time)
    • Masked Text Edit (to enforce data format rules)
    • Accounting Editor (to present and store information using currency values)
    • Percentage Editor (to present and store information using percentage values)
    • Web Image (to display an image from a given URL or a database field)
    • Web Link Edit (to display URLs and launch them in a browser)
  • XtraReports for LightSwitch
    • PAID product
    • Reporting tool
Telerik

Installing Extensions

If you didn’t install the extension from either the Visual Studio Gallery or Visual Studio Extension Manager (maybe you saved it instead, or received it in an email from a colleague), installation is as simple as clicking (or double-clicking) the extension’s setup file (VSIX) and following the installation prompts.

But to actually use the extension in your current LightSwitch project, you need to activate it for the project by selecting the extension’s check box in the column to the left of the Name column in the Extensions tab of the project’s properties, as shown in Figure 10-7.

If you want to have an extension activated by default for all future projects, select its check box in the Use in New Projects column, also shown in Figure 10-7.

Images

Figure 10-7. Activating extensions for a single project or for all future projects

If the extension that you’ve activated is a shell or a theme, you’ll also need to make a selection on the General Properties tab (see Figure 10-8).

Images

Figure 10-8. Selecting a shell and a theme

Creating Extensions

Advanced developers can extend the functionality of LightSwitch by creating their own extensions.

LightSwitch uses MEF (Managed Extensibility Framework) to enable extension elements to be defined by the developer at design-time (exported) and then consumed by LightSwitch at runtime (imported).

What You’ll Need

You’ll need three prerequisites before you can start creating extensions. The last item in the list is optional, but it will make your extension-creating life a lot easier.

  • Visual Studio 2010 Professional (or higher)
  • Visual Studio 2010 SP1 SDK (a free download)
  • Visual Studio LightSwitch 2011 (90-day trial available)
  • Visual Studio LightSwitch 2011 Extensibility Toolkit (also a free download)
Visual Studio 2010 Professional (or Higher)

The minimum version of Visual Studio that you can use to create extensions is Visual Studio Professional. You can use any of the higher versions (Premium or Ultimate), but you can’t use any of the Express versions. If you have an MSDN (Microsoft Developer Network) subscription, you should be able to download LightSwitch as part of your subscription benefits.

Visual Studio 2010 SP1 SDK

The Visual Studio 2010 SP1 (SDK (Software Development Kit)) provides tools and templates for building Visual Studio extensions. The SDK is available for free download from the Microsoft Download Center:

www.microsoft.com/download/en/details.aspx?id=21835.

images Note Because Visual Studio SP1 has to be installed for you to be able to install LightSwitch, make sure you install the SP1 version of the SDK, not the earlier RTM version.

LightSwitch 2011

To test your extensions, you’ll need either a trial version of LightSwitch or the retail version. You can obtain a copy of LightSwitch by:

LightSwitch 2011 Extensibility Toolkit

Shortly after the release of the RTM (Release to Manufacturing) version of LightSwitch, the LightSwitch 2011 Extensibility Toolkit was made available as a free download. With the release of this toolkit, the creation of extensions became a reality for more developers than ever before. It’s a huge improvement over the Extensibility Cookbook that was available in the Beta 2 time frame.

When you create an extension library (explained in an upcoming section), you can add any type of LightSwitch extension to it, or even different types of extensions. You might decide to create a separate extension library for each type of extension, or you might decide to create a suite of extensions, all contained in the one library. The choice is up to you.

The toolkit provides both VB and C# project types for creating LightSwitch extension libraries, as well as individual templates for creating themes, shells, screen templates, controls, business types, and data sources. The templates are really just an automated process to make adding an extension type to a library easier for you.

After a while, when you get used to what files make up a particular extension, you may find that it’s just as easy to create a new extension by copying and pasting the various files, especially if you decide to make modifications to the automatically generated folders and/or code.

images Tip A good example of a type of extension that you might want to put in its own project is a theme extension. A developer can choose only one theme at any particular time. The end user can’t currently change that, so including several themes in one extension may not be the best way to distribute them.

Installing the Extensibility Toolkit

To install the Extensibility Toolkit, assuming that you already have Visual Studio Professional (or higher) installed on your machine (make sure to follow the order listed below):

  1. Download and install the Visual Studio SP1 SDK from www.microsoft.com/download/en/details.aspx?id=21835.
  2. Download the LightSwitch Extensibility Toolkit from http://visualstudiogallery.msdn.microsoft.com/0dfaa2eb-3951-49e7-ade7-b9343761e1d2.
  3. Or use the Visual Studio Extension Manager to search for the toolkit and then install it.
  4. Extract the LightSwitch Extensibility Toolkit.exe file to your local machine (be sure to remember where you extracted it).
  5. Double-click the Microsoft.LightSwitch.Toolkit.vsix file.
  6. Copy the Microsoft.LightSwitch.Toolkit.targets file into one of these folders:
    • Program FilesMSBuildMicrosoftVisualStudioLightSwitchv1.0 (if you’re running a 32-bit machine)
    • Program Files (x86)MSBuildMicrosoftVisualStudioLightSwitchv1.0 (if you’re running a 64-bit machine)
  7. Launch Visual Studio.
  8. The LightSwitch Extension Library project templates will now be available under a LightSwitch/Extensibility node in the New Project dialog box.

images Caution Failure to install the SP1 SDK or to copy the target files will mean that the toolkit will not perform as expected.

Creating the Extension Library Project

We’ll be creating a single extension project to hold all of the examples in this chapter, but as mentioned earlier, you could just as easily create one project per extension type or even one project per individual extension if you really wanted to do it that way.

To create the project (see Figure 10-9):

  1. In Visual Studio Professional (or higher), click on File Images New Project.
  2. The New Project dialog opens
  3. Select the LightSwitch node.
  4. Select either the VB or C# version of LightSwitch Extension Library.
  5. Enter the project’s location and name. This example uses Central.Extensions.
  6. Click OK.
Images

Figure 10-9. New Project dialog box

You should now have a Visual Studio solution that initially contains seven projects, as shown in Figure 10-10.

Images

Figure 10-10. Solution Explorer showing the seven generated projects

images Caution Be careful not to give your extension project a name that is too long.The extensibility toolkit project template can run into a character limit when the whole path is taken into consideration. Long names can result in an error message:

Images

Let’s look at each of the projects in detail, so you know why they exist, as well as which parts of your extensions go into which projects, and why.

The Client Project

The Client project is a Silverlight project that contains client implementations that should be deployed with a LightSwitch application but are not found in the Common project (for example, controls, shells, and themes). The classes/files in this project are used to display the extension in the client application.

Client Folders

When the Client project is initially created by the template, it has no folders or files:

Images

Each extension type can create the Presentation folder if it hasn’t already been created by another extension. However, no extension type adds files directly to the actual folder itself.

Images

Client Subfolders

Each extension type can add its own subfolder to the Presentation folder:

Images

The Client.Design Project

The Client.Design project is a Silverlight project that contains the implementations necessary during the debugging of a LightSwitch application (for example, control images or custom property editors for the runtime screen designer). The classes/files in this project are used in the Design Screen experience.

Client.Design Folders

When the project is initially created, it has no folders:

Images

As with the Presentation folder in the Client project, some extension types will add a Resources folder if it doesn’t already exist, but no extension type adds files directly to the folder itself.

Images

Client.Design Subfolders

A control extension or business type extension will add a ControlImages subfolder to the Resources folder. You can add further subfolders to it manually, as shown in Figure 10-11, in order to better organize the elements that get added to it by the extension templates (remember to manually move the files that the templates create, though).

For a single extension, this might not really be an improvement, but the more extensions that you add to an extension library, the more this will help. (Being able to collapse folders that you’re not working on is a big advantage here.)

Images

Figure 10-11. Organizing the ControlImages files into subfolders

The Common Project

The Common project is a Silverlight project that primarily contains the extension’s metadata definitions, along with any code that runs on the middle tier (on both the client and on the server), such as metadata loaders and validators.

The metadata definitions are contained in LSML files, each of which represents a model fragment that is merged with all other model fragments at runtime.

When first created, the Common project has two folders, Metadata and Resources:

Images

Metadata Folder and Files

The Metadata folder contains files that define and load metadata, both for the extension library itself and for any extension types that are added to it. The Metadata folder initially contains two files, Module.lsml and ModuleLoader.vb/cs:

Images

The Module.lsml file simply contains a small XML model fragment that declares a module name for the extension. There’s only one of these files per extension library.

The purpose of the ModuleLoader class is to define the ResourceManager that’ll be used by the extension to find its resources, and to define a ModuleLoader class to load any model fragments (LSML files) that have been added to the extension’s assembly as a resource.

The ModuleLoader class has a Friend/Internal1 modifier, meaning that it can be accessed by code that’s in the same assembly, but not from code that’s outside the assembly. There’s only a single instance of this class per extension library.

The class is decorated with two attributes:

  • Export attribute, to alert the LightSwitch application that this class exports an implementation of IModuleDefinitionLoader
  • ModuleDefinitionLoader attribute, which provides the String value of the extension’s name (Central.Extensions)

It implements a single interface, IModuleDefinitionLoader, which contains two methods:

  • GetModelResourceManager sub (void function in C#), which returns the instance of a ResourceManager that the extension should use to find its resources
  • LoadModelFragments function, which returns an IEnumerable(Of Stream) that gets populated with any file with an LSML file extension

The Metadata folder doesn’t initially contain any subfolders, but each extension type can add its own subfolder:

Images

________________________

1Access modifiers are keywords used to specify the declared accessibility of a member, or a type:

  • Public / public: access is not restricted
  • Protected / protected: access is limited to the containing class, or types derived from the containing class
  • Friend / internal: access is limited to the current assembly
  • Protected Friend / protected internal: access is limited to the current assembly, or types derived from the containing class
  • Private / private: access is limited to the containing type
Resources Folder and Files

The Resources folder contains resource files, both for the extension library and for any extension types that are added to it. The Resources folder is created with only a single file in it:

Images

The ModuleResources.resx file contains any embedded resources, such as localized strings, which are added via the Resource Editor. Initially there aren’t any resources in it.

The Design Project

The Design project is a WPF project, and contains elements such as design-time controls, images, and supporting code (for example, a screen template). The classes/files in this project are used for the design-time experience in the IDE (such as designing a screen).

At first, it may seem like the files in this project are redundant duplicates of the files in the Client.Design project, but the difference is that the Client.Design project is a Silverlight project, used for the display of the extension’s UI elements in the Silverlight client, and the Design project is a WPF project, used for the display of the extension’s elements in the Visual Studio IDE.

Design Folders

When the project is initially created, it has no folders:

Images

As with the Resources folder in the Client.Design project, some extension types will add a Resources folder if it doesn’t already exist, but no extension type adds files directly to the folder itself.

Images

Design Subfolders

A control extension or business type extension will add a ControlImages subfolder. You can add further subfolders to it manually, as shown in Figure 10-12, to better organize the elements that are added to it by the extension templates (you’ll have to manually move the files that the templates create, though).

Images

Figure 10-12. Organizing the ControlImages files into subfolders

The Server Project

The Server project is a .NET project that contains server implementations that should be deployed with a LightSwitch application but are not found in the Common project (for example, data sources). It has access to assemblies of the full .NET Framework.

Server Folders

When the project is initially created, it has no folders:

Images

A data source extension item creates a DataSources folder if it hasn’t already been created by another data source extension, but no files are added directly to the folder itself.

Images

The Lspkg Project

This project exists only as a place to pull all of the other projects together, for packaging into the VSIX file. It packages the previous five projects so that LightSwitch can unpack and reference them when the package is installed.

If you watch carefully, you may notice that files and folders are created in this project, and then they’re moved to one of the other projects. Interesting technique!

Occasionally you might also see errors displayed that tell you that you can’t mix platform types. The error message states:

The project ‘ExtensionName.ProjectName’ cannot be referenced. The referenced project is targeted to a different framework family (Silverlight).

These particular errors can safely be ignored, because the project doesn’t generate any code. You’ll also find that a project/solution rebuild will usually make them go away. But they can be a bit disconcerting when you see them for the first time.

Lspkg Folders

When the extension project is first created, the Lspkg project contains no folders or files:

Images

You add a template item by right-clicking the Lspkg project and then selecting Add Images New Item. The Add New Item dialog box opens, as shown in Figure 10-13.

Images

Figure 10-13. Adding a new extension template item

When you add a template item, one or more folders or files may be added to some of the other projects, depending on the type of item you’re adding.

The VSIX Project

This project packages the generated LSPKG file into a VSIX package so that it can be added to LightSwitch through the Extension Manager. It initially contains only a single file:

Images

Any VSIX-supported project template, including a LightSwitch extension library, generates a manifest file and calls it source.extension.vsixmanifest. When Visual Studio builds the project, it copies the content of this file into Extension.VsixManifest in the VSIX package. The package file is actually a simple ZIP file that uses the Open Packaging Conventions.

Exploring the VSIX Manifest Designer

There’s usually no need to edit the manifest file manually. You can set the properties by using the VSIX Manifest Designer to modify the source.extension.vsix manifest file in the VSIX project. Simply double-click the file to open it in the editor (see Figure 10-14).

Images

Figure 10-14. source.extension.vsix manifest open in the VSIX Manifest Designer

The VSIX Manifest Designer goes further than just providing an easy way to edit the VSIX manifest’s XML contents. It integrates into Visual Studio to simplify the process of adding content to the VSIX file.

When the Icon setting, the Preview Image setting, or the License Terms setting is specified via the Manifest Editor, the corresponding files are added to the project if they are not already present. The Include in VSIX property for those files is also set to true, so they’ll be copied into the VSIX file that’s generated when the project is built (or rebuilt).

Let’s look at each of the VSIX’s manifest settings individually. We’ve sorted them into two categories:

  • External settings, which are displayed externally
  • Internal settings, which are used internally
External Settings

The values for these manifest settings determine what information appears for your extension in:

  • Extension Manager (see Figure 10-15)
    • Installed Extensions tab (when an extension has been installed)
    • Online Gallery tab (when you’re searching for extensions)
    • Updates tab (when an update is available for the extension)
  • Visual Studio Gallery web site
Images

Figure 10-15. Extension Manager showing entered settings

The value for the License Terms setting is also displayed in the Visual Studio Extension Installer (see Figure 10-16), as the extension is being installed.

Images

Figure 10-16. Visual Studio Extension Installer showing license terms

Product Name Setting

The value of this setting is displayed as the Name value in the Extensions tab of the LightSwitch project, and in the Extension Manager. The default is the name that you supplied for the extension library (solution name), but it can be changed at any time, to whatever you want to call your product.

The maximum length for this setting is 60 characters.

Author Setting

The value of this setting is displayed as the Created By value in the Extensions tab, and in the Extensions Manager. The default is the Company Name that was entered when you installed Visual Studio. You can change this property to anything you like, but it’s a good idea to be consistent.

The maximum length is 50 characters.

Version Setting

The version number that you enter here will be used by the Extension Manager to determine whether there is a new version (update) of the extension. The Extension Manager won’t allow the VSIX to be installed if there’s already an extension installed with the same version number (or higher).

The maximum length is 23 characters.

SAMPLE VERSIONING SYSTEM

images Tip If you have the Visual Studio Productivity Power Tools extension installed, you might find it helpful to pin the manifest file in Visual Studio, so it’s always available for you during development and debugging of your extension. You can find yourself changing the build number often as you test or fix your extension’s functionality.

Description Setting

The value of this setting is displayed as the Description value for the selected extension in the Extensions tab, as well as in the Extension Manager. The default is the solution name plus the word description.

It’s best to keep the description fairly short, if possible, because although the gallery web page will display several lines, as will the Extensions tab, the Extension Manager will display only two lines. It may look odd if your description is cut off after two lines. You can change the Description setting at any time.

The maximum length is 1,024 characters.

Icon Setting

Here you can specify an ICO, BMP, JPG, GIF, JPG, PNG, or TIFF file that will be displayed beside the extension name. Specifying an icon file is optional but highly recommended. A default image will be used if you don’t supply one.

Preview Image Setting

This optional setting allows you to specify a BMP, JPG, GIF, PNG, or TIFF file that shows a preview of what the extension looks like. The same image that was specified for the Icon setting will be used if you don’t supply a value here.

Microsoft’s documentation for this setting suggests that you should use an image that is 200200 pixels, but you might want to find out for yourself what gives you the best result.

More Info URL Setting

Here you can enter an HTTP/HTTPS URL that points to a web page that has more information about your extension. A More Information link will be displayed in the Extension Manager and in the Visual Studio Gallery.

If you don’t specify a URL, the hyperlink is disabled.

Getting Started Guide Setting

This setting allows you to enter an HTTP/HTTPS URL that points to a web page indicating how to get started with your extension. A Getting Started link will be displayed in the Extension Manager and in the Visual Studio Gallery.

If you don’t specify a URL, the hyperlink is disabled.

Internal Settings

Internal settings aren’t exposed to the consumer of the extension. They’re used internally by the Extension Manager.

ID Setting

This setting is the extension’s unique identifier. This value is used by the Extension Manager to identify when a new version of the extension is being deployed. You can’t install two extensions that have the same ID in the same installed instance of Visual Studio.

Be careful what you use here, because if you change it later, any future versions of your extension won’t be recognized as an update to the original extension. We learned this lesson the hard way, but now you know about it, so you can avoid this problem.

The value is initially set to the name that you supplied for the extension library (the solution name), but it can be changed to anything you like. You won’t see it anywhere, though, because it is used only internally.

The maximum length is 100 characters.

Locale Setting

This setting determines the intended locale of your extension. The default value is the locale of the installed version of Visual Studio. Only a limited number of locales are currently available (see Figure 10-17).

Images

Figure 10-17. Available locales

Supported VS Editions Setting

Figure 10-18 shows a hierarchy diagram of the various Visual Studio editions that an extension can normally support. The Express editions aren’t supported for LightSwitch extensions, of course.

The default values for this setting are as follows:

  • Visual Studio 2010
  • VSLS (in Additional Visual Studio Products)
Images

Figure 10-18. Supported Visual Studio Versions

images Caution Don’t change the values in this property. LightSwitch will recognize your extensions only if the default values haven’t been changed.

The Extension Manager will allow the extension to be installed only if the version of Visual Studio that’s currently installed on the machine (or a higher version) has been specified in this dialog box. The LightSwitch extension project template automatically selects Visual Studio 2010, as well as Additional Visual Studio Products. It also adds VSLS in the additional versions field, as you can see in Figure 10-19.

Images

Figure 10-19. Select Visual Studio Version and Edition dialog box

License Terms Setting

This setting allows you to include a TXT or RTF file that describes the extension’s terms of use or licensing agreement. This will be displayed in the Visual Studio Extension Installer’s dialog box during installation.

It’s an optional setting, and the default is empty. If you don’t enter the name of a file, the installer will display Your license terms go here.

Supported Framework Runtime Setting

These two values are automatically set for you. In LightSwitch 2011:

  • The Min value is set to 4.0 (the current version of the .NET Framework)
  • The Max value is set to 4.5 (the next version of the .NET Framework)

images Caution LightSwitch requires version 4.0. The extension may not install if you change these values.

Understanding Extensions

In the previous section, we explored the different projects that a LightSwitch extension is composed of. As you saw, not all projects are used by all extension types. However, each extension type has its own unique set of requirements. The most basic of these are certain attributes and interface implementations.

On the one hand, attributes enable LightSwitch to know what features your extension is offering, whether it’s a theme extension or a shell extension, and so on. Attributes can also provide some basic information about the extension itself, such as an ID, a name, or even a version number. LightSwitch imports extensions, via MEF, that are made known to it through the use of the Export attribute and a contract value. This contract must match the contract that LightSwitch is expecting for a particular extension type.

On the other hand, interfaces give LightSwitch a way of consuming your extension by being able to make assumptions about their behavior in a consistent manner. The interfaces that LightSwitch provides determine what an extension can do, without having to have exact knowledge of how that’s achieved.

Because of publishing deadlines, and to keep the chapter to a manageable length, we weren’t able to include step-by-step instructions for each of the extension types, as much as we would have liked to. There’s a huge amount of information to absorb regarding to how create extensions. Each extension type could easily be its own chapter. Each of the control type extensions could also fill a chapter of their own as well.

So although we could have written much, much more on actually creating extensions, we’ve chosen to concentrate on helping you understand them and hopefully provide the “missing” information that’s hard to find anywhere else, or that’s scattered all over the Internet. Microsoft and a few others have written articles that walk through creating various types of extensions, but without the background information, these articles can be hard to follow, or worse, hard to understand.

We hope that we’ll able to follow up this book with more-specific extension-related articles. Be sure to visit LightSwitch Central (www.lightswitchcentral.net.au) for related blog posts, articles, or downloads.

Let’s now have a look at understanding each of the extension types in a bit more detail.

Understanding Theme Extensions

As mentioned earlier in the chapter, a theme extension allows you to change your application’s visual impact (the look part of look and feel). You do this by changing the font and color values, and by specifying alternative values for the various brushes that are used by your LightSwitch application’s shell, screens, and controls. You could create a theme to make your application match your company’s colors, for example.

A theme extension can contain two implementation types: a Theme and a somewhat unfortunately named ThemeExtension (not to be confused with an actual theme extension). It probably would have been a lot less confusing if it had been called something like a StyleExtension or a ControlStyleExtension, but its name comes from the fact that it’s an extension to a theme, in the form of additional control styles.

Web sites often use what’s called a style sheet, usually referred to as CSS (Cascading Style Sheets) to define the colors and fonts, as well as the control styles, for the entire site in one place. LightSwitch defines its color and font information in a Theme, which is stored in a ResourceDictionary in a XAML file. It can also define control styles in a ThemeExtension, which is also stored in ResourceDictionaries in one or more XAML files.

By using themes, it’s easy to change the colors for the entire application in one place, just by selecting a different theme. By using control styles, it’s easy to change the way various controls look in the application, again all defined in one place.

The attributes and interfaces that a theme extension requires are found in the Microsoft.LightSwitch.Theming namespace.

Creating a Theme Extension

There are a few simple steps required to create a theme extension:

  1. Create an extension library, as described earlier in the chapter (or you can add to an existing extension library).
  2. Right-click the LSPKG project (Central.Extensions.lspkg)
  3. Select Add Images New Item.
  4. Click the Theme option (see Figure 10-20).
  5. Provide a name for the theme (we’ll call it CentralTheme).
  6. Click Add.
  7. The template adds various folders and files (discussed later in this section).The code that’s necessary to implement the required interfaces is provided by the template (we’ll examine this next).
  8. Modify the XAML that was provided by the template, to define the brush values and/or control styles for your theme.
Images

Figure 10-20. Adding a new theme extension template item

Using Theme Extension Attributes

Two attributes must be applied to any class that defines a theme, for it to be recognized by LightSwitch. Two attributes also need to be applied to any class that defines a ThemeExtension (not to be confused with a Theme extension), for it to be recognized by LightSwitch. Table 10-1 lists these four attributes.

Images

Listing 10-1 shows these attributes being used in code, to decorate the class that defines a theme.

Listing 10-1. Theme-Related Attributes Being Used in Code

VB:

File: N/A

Friend Const ThemeId As String = "Central.Extensions:CentralTheme"
Friend Const ThemeVersion As String = "1.0"

<Export(GetType(ITheme))>
<Theme(CentralTheme.ThemeId, CentralTheme.ThemeVersion)>
Public Class CentralTheme
    Implements ITheme
    Implements IThemeExtension

    'implementation code goes here
End Class

C#:

File: N/A

internal const string ThemeId = "Central.Extensions:CentralTheme";
internal const string ThemeVersion = "1.0";

[Export(typeof(ITheme))]
[Theme(CentralTheme.ThemeId, CentralTheme.ThemeVersion)]
public class CentralTheme : ITheme, IThemeExtension
{

    //implementation code goes here
}

Using Theme Extension Interfaces

In addition to being decorated with the two attributes just described, a class that defines a Theme item must also implement the ITheme interface. You can also optionally implement IThemeExtension.

A theme extension can have one or more ITheme implementations, as well as one or more IThemeExtension implementations, though in practice you’d probably really want only one of either in a single theme extension. You can, of course, have multiple theme extensions in a single extension library.

ITheme Interface

The ITheme interface consists of three properties, shown in Table 10-2. The default values are based on the extension library name (CentralExtensions) and the theme extension pathname (Central/CentralTheme).

Images

IThemeExtension Interface

The IThemeExtension interface has only one method to implement, GetControlStyleResources, which must return an IEnumerable(Of Uri). Its purpose is to expose one or more URI values that each point to a ResourceDictionary (stored in a XAML file) that contains control style definitions. The method has three parameters: themeId, themeVersion, and modules.

Theme Element Load Order

A LightSwitch application will load theme-related information in the following order:

  1. The default ColorAndFontScheme
  2. Your ITheme implementation’s ColorAndFontScheme
  3. The default ControlStyleResources
  4. Your IThemeExtension’s ControlStyleResources

Theme Extension Implementation

Let’s look at what happens when you use the Extensibility Toolkit to add a theme. As we mentioned before, once you know what the template is doing for you, it can be almost as quick to copy/paste/edit an existing theme. This is especially true if you decide to change any of the locations of the various files, as we will in the example.

The following paragraphs assume that we’ve called our theme CentralTheme.

Client Project’s Elements

When we add a theme, using the Extensibility Toolkit’s Theme template, as we mentioned earlier in the chapter, a Themes folder is added to the Client project’s Presentation folder for us (see Figure 10-21).

We recommend creating a separate folder for each theme in the Themes folder, and moving the files created by the template into it. You don’t have to do this, but it helps keep the project more organized. For our example theme, we’ll create a folder called Central and move the files into that folder.

Images

Figure 10-21. Client project’s Themes folder

The Class File

The CentralTheme class contains the ITheme implementation (see Listing 10-2) that we discussed earlier. Because we moved the files for the theme into their own folder, we also have to make a small change to the ColorAndFontScheme property’s value, changing /Themes/ to /Themes/Central/ in order to reflect the folder change.

You could also put the code for any IThemeExtension implementations in this file, or you could put them in a file of their own, or even a file per ThemeExtension.

images Caution  If you move the XAML file to a different folder than the one the template put it in, as we have, make sure that you edit the Theme class so that the ColorAndFontScheme property points to the correct location.

Listing 10-2. CentralTheme Class’s Code

VB:

File: Central.ExtensionsCentral.Extensions.ClientPresentationThemesCentralCentralTheme.vb

Imports System
Imports System.ComponentModel.Composition
Imports System.Collections.Generic
Imports Microsoft.LightSwitch.Theming
Imports Microsoft.LightSwitch.Model

<Export(GetType(ITheme))>
<Theme(CentralTheme.ThemeId, CentralTheme.ThemeVersion)>
<Export(GetType(IThemeExtension))>
<ThemeExtension(CentralTheme.ThemeId)>
Public Class CentralTheme
    Implements ITheme
    Implements IThemeExtension

    'constants
    Friend Const ThemeId As String = "Central.Extensions:CentralTheme"
    Friend Const ThemeVersion As String = "1.0"

    'ITheme members
    Public ReadOnly Property ColorAndFontScheme As UriImages
    Implements ITheme.ColorAndFontSchemeImages
        Get
           'this is a modified version of what appears in the file created by the template
            Dim uriString = String.Format("{0}{1}{2}"Images
                , "/Central.Extensions.Client;"Images
                , "component/Presentation/Themes/Central/"Images
                , "CentralTheme.xaml"Images
                )
            Return New Uri(uriString, UriKind.Relative)
        End Get
    End Property

    Public ReadOnly Property Id As StringImages
    Implements ITheme.Id
        Get
            Return CentralTheme.ThemeId
        End Get
    End Property

    Public ReadOnly Property Version As StringImages
    Implements ITheme.Version
        Get
            Return CentralTheme.ThemeVersion
        End Get
    End Property

    'IThemeExtension members
    Public Function GetControlStyleResources(Images
          ByVal themeId As StringImages
        , ByVal themeVersion As StringImages
        , ByVal modules As IEnumerable(Of IModuleDefinition)Images
        ) As IEnumerable(Of Uri)Images
    Implements IThemeExtension.GetControlStyleResources
        'this is a modified version of what appears in the file created by the template
        Dim uriString =String.Format("{0}{1}{2}"Images
            , "/Central.Extensions.Client;"Images
            , "component/Presentation/Themes/"Images
            , "CentralTemplates.xaml"Images
            )
        Dim result as new List(Of Uri) FromImages
            {
                New Uri(uriString, UriKind.Relative)
            }

        Return result
    End Function

End Class

C#:

File: Central.ExtensionsCentral.Extensions.ClientPresentationThemesCentralCentralTheme.cs

using System;
using System.ComponentModel.Composition;
using System.Collections.Generic;
using Microsoft.LightSwitch.Theming;
using Microsoft.LightSwitch.Model;

[Export(typeof(ITheme)), Theme(CentralTheme.ThemeId, CentralTheme.ThemeVersion)]
[Export(typeof(IThemeExtension)), ThemeExtension(CentralTheme.ThemeId)]
public class CentralTheme : ITheme, IThemeExtension
{
    //constants
    internal const string ThemeId = "Central.Extensions:CentralTheme";
    internal const string ThemeVersion = "1.0";

    //ITheme members
    public Uri ColorAndFontScheme
    {
        get
        {
           //this is a modified version of what appears in the file created by the template
            var uriString = string.Format("{0}{1}{2}"Images
                , "/Central.Extensions.Client;"Images
                , "component/Presentation/Themes/Central/"Images
                , "CentralTheme.xaml"Images
                );
            return new Uri(uriString, UriKind.Relative);
        }
    }

    public string Id
    {
        get
        {
            return CentralTheme.ThemeId;
        }
    }

    public string Version
    {
        get
        {
            return CentralTheme.ThemeVersion;
        }
    }

    //IThemeExtension members
    public IEnumerable<Uri> GetControlStyleResources(Images
          string themeIdImages
        , string themeVersionImages
        , IEnumerable<IModuleDefinition> modulesImages
        )
    {
        //this is a modified version of what appears in the file created by the template
        var uriString = string.Format("{0}{1}{2}"Images
            , "/Central.Extensions.Client;"Images
            , "component/Presentation/Themes/"Images
            , "CentralTemplates.xaml"Images
            );

        List<Uri> result = new List<Uri>()
            {
                new Uri(uriString, UriKind.Relative)
            };

        return result;
    }
}
The XAML File

The XAML file contains a ResourceDictionary, which defines the colors and brushes for the theme, but is far too large to include here in its entirety. Instead, we’ll examine the various categories of styles that are defined, along with any details that you’ll need to know but that might not be so obvious.

Text Styles

There are 11 predefined text style definitions, as shown in Table 10-3.

Images

Images

Each of these styles has a number of font substyles that can be also set for it, as shown in Table 10-4.

Images

Images

Brush Definitions

The rest of the rather large XAML file consists of a series of brush definitions, grouped into style groups, as shown in Table 10-5. A color value is provided for every brush that’s used in a theme by default. (Custom themes can add new style definitions, but it’s not advisable to do so, because most of the themes that will be available won’t be aware of your custom definitions.)

The hardest part of creating a theme extension is deciding and testing which colors to use for the various brush definitions, and then entering them into the XAML. A tool such as Microsoft Expression Blend can be useful here, but it’s still a fairly tedious process.

Table 10-5 shows the groups of brushes that are found in the XAML file that defines a theme’s colors. In most cases, you can derive the actual brush name by taking the value from the Group column, and then adding the value from the Brush column, plus one of the states mentioned in the Description column (except for Normal), and finally adding the word Brush on the end.

So, for the Screen group, you’d end up with three brushes called ScreenBackgroundBrush, ScreenLoadingBackgroundBrush, and ScreenControlBorderBrush. For the Button group, you’d have five brushes called ButtonBorderBrush, ButtonBorderFocusedBrush, ButtonBorderMouseOverBrush, ButtonBorderDisabledBrush, and ButtonBorderPressedBrush.

In the XAML file that the template produces for you, you’ll see that some brushes are SolidColorBrushes, some are LinearGradientBrushes, and a few are RadialGradientBrushes. You don’t have to keep the same type of brush that’s defined in the template’s XAML. You can change a SolidColorBrush into a LinearGradientBrush, or vice versa. As long as you provide some type of brush, you have complete freedom to create whatever effects that you want to achieve.

Images

Images

Images

Images

Images

Images

Images

Images

Images

Images

Common Project’s Elements

When we add a theme, using the Extensibility Toolkit’s Theme template, as described earlier in the chapter, a Themes folder is added to the Common project’s Metadata folder for us (see Figure 10-22).

Because only one file is added per theme, there’s not really any need to create a separate folder for each theme’s LSML file, but of course you could if you wanted to. The file for our theme is called CentralTheme.lsml.

Images

Figure 10-22. Common project’s Themes folder

The LSML File

The CentralTheme.lsml file contains a model fragment that defines the theme’s details, as shown in Listing 10-3. Two attributes are defined in it (see Table 10-6).

Images

Listing 10-3. CentralTheme’s LSML file

XAML:

File: Central.Extensions.CommonMetadataThemesCentralTheme.lsml

<?xml version="1.0" encoding="utf-8" ?>
<ModelFragment
  xmlns="http://schemas.microsoft.com/LightSwitch/2010/xaml/model"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  
  <Theme Name="CentralTheme">
    <Theme.Attributes>
      <DisplayName Value="Central Theme"/>
      <Description Value="Central Theme description"/>
    </Theme.Attributes>
  </Theme>
</ModelFragment>

Activating LightSwitch’s “Hidden” Theme

Earlier, we mentioned the so-called hidden theme that uses Windows system colors to create a high- contrast theme. Now that we’ve explained the steps required to create a theme, for a bit of fun we can show you how to activate this theme:

  1. Add a theme template item (by right-clicking the Lspkg project).
  2. Call it HiddenTheme.
  3. Modify the URI in ColorAndFontScheme (in the HiddenTheme.vb/cs file, located in the Client project) to match Listing 10-4.
  4. Modify the attributes in HiddenTheme.lsml (located in the Common project) to put a space between Hidden and Theme (for display purposes).
  5. Delete the HiddenTheme.xaml file that was created by the template (it’s not needed).

We don’t actually need the XAML file that the template created for us this time, because the brush definitions have already been defined in one of LightSwitch’s assemblies, Microsoft.LightSwitch.Client.Internal. All we need to do is just point to that XAML resource in our code.

images Caution  Be aware that the next version of LightSwitch might not contain that particular piece of XAML in that particular assembly, or even at all.

Listing 10-4. Code Required to Access the “Hidden” Theme

VB:

File: Central.UtilitiesPresentationThemesHiddenHiddenTheme.vb

<Export(GetType(ITheme))>
<Theme(HiddenTheme.ThemeId, HiddenTheme.ThemeVersion)>
Friend Class HiddenTheme
Implements ITheme
    'constants
    Friend Const ThemeId As String = "Central.Extensions:HiddenTheme"
    Friend Const ThemeVersion As String = "1.0"

    'ITheme members
    Public ReadOnly Property ColorAndFontScheme As UriImages
    Implements ITheme.ColorAndFontScheme
        Get
            'this is a modified version of what appears in the file
            'created by the template
            Dim uriString = String.Format("{0}{1}{2}"Images
                , "/Microsoft.LightSwitch.Client.Internal;"Images
                , "component/Screens/ScreenPresentation/Implementations/Resources/Themes/"Images
                , "Black/Black_VisualPalette.xaml"
                )

            Return New Uri(uriString, UriKind.Relative)
        End Get
    End Property

    Public ReadOnly Property Id As StringImages
    Implements ITheme.Id
        Get
            Return HiddenTheme.ThemeId
        End Get
    End Property

    Public ReadOnly Property Version As StringImages
    Implements ITheme.Version
        Get
            Return HiddenTheme.ThemeVersion
        End Get
    End Property
End Class

C#:

File: Central.UtilitiesPresentationThemesCentral.cs

[Export(typeof(ITheme)), Theme(HiddenTheme.ThemeId, HiddenTheme.ThemeVersion)]
internal class HiddenTheme : ITheme
{
    //constants
    internal const string ThemeId = "Central.Extensions:HiddenTheme";
    internal const string ThemeVersion = "1.0";

    //ITheme members
    public Uri ColorAndFontScheme
    {
        get
        {
            //this is a modified version of what appears in the file
            //created by the template
            var uriString = string.Format("{0}{1}{2}"Images
               , "/Microsoft.LightSwitch.Client.Internal;"Images
               , "component/Screens/ScreenPresentation/Implementations/Resources/Themes/"Images
               , "Black/Black_VisualPalette.xaml"Images
               );

            return new Uri(uriString, UriKind.Relative);
        }
    }

    public string Id
    {
        get
        {
            return HiddenTheme.ThemeId;
        }
    }

    public string Version
    {
        get
        {
            return HiddenTheme.ThemeVersion;
        }
    }
}

Renaming a Theme

Sometimes, after you’ve added a theme, you might need to rename it for some reason. Although you could just delete the original theme and add a new one, we’ll show you the various places where the name needs to be changed. This will also be helpful if you decide to copy/paste/edit a theme, instead of using the template to create a new theme.

These instructions assume that you’ve followed our previous advice and have moved the theme to its own folder.

  1. In the Client project
    • rename the theme’s folder from
      ClientPresentationThemesOldFolderName to
      ClientPresentationThemesNewFolderName
    • rename the theme’s class file from
      ClientPresentationThemesNewFolderNameOldThemeName.vb/cs to
      ClientPresentationThemesNewFolderNameNewThemeName.vb/cs
    • change the Theme class’s ThemeId from
      "Central.Extensions:OldThemeName" to
      "Central.Extensions:NewThemeName"
    • change the Theme class’s ColorAndFontScheme URI path from
      "/Central.Extensions.Client;component/Presentation/Themes/Images
      OldTemplatesName.xaml" to
      "/Central.Extensions.Client;component/Presentation/Themes/Images
      NewTemplatesName.xaml"
    • rename the theme’s XAML file from
      ClientPresentationThemesNewFolderNameOldThemeName.xaml to
      ClientPresentationThemesNewFolderNameNewThemeName.xaml
  2. In the Common project
    • rename the LSML file from
      CommonMetadataThemesOldThemeName.lsml to
      CommonMetadataThemesNewThemeName.lsml

Microsoft’s Theme Extension Sample

Microsoft has made a sample theme available for download in the MSDN Samples Gallery: http://code.msdn.microsoft.com/LightSwitch-Metro-Theme-b1bfce24. It’s quite a complex theme that not only defines fonts and colors, but also adds a number of ThemeExtensions, which define new appearances and behaviors for some of the built-in LightSwitch controls.

You might find that visually this theme is quite a jarring experience, with uppercase and lowercase fonts appearing in unusual places. However, it’s actually based on the new Metro style that Windows 8 and Windows Phone 7 have introduced. Some people like it, others not so much.

Hidden away in the theme (well, not really hidden, but you do have to go looking) are an abundance of interesting and helpful techniques for anyone who wants to explore the theme in more depth.

Understanding Shell Extensions

In addition to theme extensions, shell extensions also allow you to change your application’s visual impact (the feel part of look and feel), by creating an application shell with a potentially completely different layout, and even different capabilities than the standard application shell that comes with LightSwitch.

The attributes and interfaces required by the shell extension classes are found in the Microsoft.LightSwitch.Runtime.Shell namespace.

Creating a Shell Extension

There are a few simple steps required to create a shell extension:

  1. Create an extension library, as described earlier in the chapter (or you can add to an existing extension library).
  2. Right-click the LSPKG project (Central.Extensions.lspkg)
  3. Select Add Images New Item.
  4. Click the Shell option, shown in Figure 10-23.
  5. Provide a name for the shell (we’ll call it CentralShell).
  6. Click Add.
  7. The template adds various folders and files (discussed later in this section). The code that’s necessary to implement the required interfaces is also provided by the template (we’ll examine this next).
  8. Modify the XAML provided by the template to define the layout and content of your shell.
Images

Figure 10-23. Adding a new shell extension template item

Using Shell Extension Attributes

Two attributes must be applied to any class that defines a Shell, for it to be recognized by LightSwitch (see Table 10-7).

Images

Listing 10-5 show the attributes being used in code, to decorate the class that defines a shell extension.

Listing 10-5. The Shell Attributes Being Used in Code

VB:

File: N/A

Friend Const ShellId As String = "Central.Extensions:CentralShell"

<Export(GetType(IShell))>
<Shell(CentralShell.ShellId)>
Public Class CentralShell
    Implements IShell

    'implementation code goes here
End Class

C#:

File: N/A

internal const string ShellId = "Central.Extensions:CentralShell";

[Export(typeof(IShell))]
[Shell(CentralShell.ShellId)]
public class CentralShell : IShell
{

    //implementation code goes here
}

Using the Shell Extension Interface

In addition to being decorated with the two attributes just described, a class that defines a shell must also implement the IShell interface.

The IShell interface consists of two properties, listed in Table 10-8.

Images

Shell Extension Implementation

A shell enables users to interact with the application. It provides the navigation menu items and displays screens, associated commands, current user information, and other useful information. Let’s look at how some of that is defined.

The following paragraphs assume that we’ve called our theme CentralShell.

Client Project’s Elements

When we add a shell, using the Extensibility Toolkit’s Shell item, as we mentioned earlier, a Shells folder and a ShellsComponents folder are added to the Client project’s Presentation folder for us, as shown in Figure 10-24.

We recommend creating a separate folder for each theme in the Shells folder and moving the files created by the template into it. Once again, you don’t have to do this, but it helps keep the project more organized. For our example theme, we’ll create a folder called Central and move the files into that folder (the Components folder seems unnecessary, so we’ve deleted it, but it’s up to you what you do with it in your own projects).

Three files get added to the Shells folder.

Images

Figure 10-24. Client project’s PresentationShells folder

The Class File

The CentralShell class contains the IShell implementation (see Listing 10-6) that we discussed earlier.

Because we moved the files for the shell into their own folder, we also had to make a small change to the ShellUri property’s value, changing /Shells/ to /Shells/Central/ in order to reflect this folder change.

Listing 10-6. CentralShell Class’s Code

VB:

File: Central.Extensions.ClientPresentationShellsCentralCentralShell.vb

Imports System
Imports System.ComponentModel.Composition

Imports Microsoft.LightSwitch.Runtime.Shell

Namespace Presentation.Shells.Components

    Friend Const ShellId As String = "Central.Extensions:CentralShell"

    <Export(GetType(IShell))>
    <Shell(CentralShell.ShellId)>
    Friend Class CentralShell
        Implements IShell

        Public ReadOnly Property Name As StringImages
        Implements IShell.Name
            Get
                Return CentralShell.ShellId
            End Get
        End Property

        Public ReadOnly Property ShellUri As UriImages
        Implements IShell.ShellUri
            Get
                'this is a modified version of what appears in the file
                'created by the template
                Dim uriString = String.Format("{0}{1}{2}"Images
                    , "/Central.Extensions.Client;"Images
                    , "component/Presentation/Shells/Central/"Images
                    , "CentralShell.xaml"Images
                    )
                Return New Uri(uriString, UriKind.Relative)
            End Get
        End Property

    End Class

End Namespace

C#:

File: Central.Extensions.ClientPresentationShellsCentralCentralShell.cs

using System;
using System.ComponentModel.Composition;

using Microsoft.LightSwitch.Runtime.Shell;

namespace Presentation.Shells.Components
{
    internal const string ShellId = "Central.Extensions:CentralShell";

    [Export(typeof(IShell)), Shell(CentralShell.ShellId)]
    internal class CentralShell : IShell
    {
        public string Name
        {
            get
            {
                return CentralShell.ShellId;
            }
        }

        public Uri ShellUri
        {
            get
            {
                //this is a modified version of what appears in the file
                //created by the template
                var uriString = string.Format("{0}{1}{2}";Images
                   , "/Central.Extensions.Client;"Images
                   , "component/Presentation/Shells/Central/"Images
                   , "CentralShell.xaml"Images
                   );
                return new Uri(uriString, UriKind.Relative);
            }
        }
    }
}

Images Caution  If you move the XAML file to a different folder than the one the template put it in, as we have, make sure that you edit the Shell class so that the ShellUri property points to the correct location.

The XAML File

The CentralShell.xaml file contains the XAML that represents the controls and the layout of the shell itself (see Listing 10-7). By default, the shell is based on a UserControl that simply contains an empty Grid. You can replace the grid with the XAML that’s required to display your intended components.

The x:Class name has to match the name of the class in the code-behind file. The xmlns definitions are the XML namespaces that Silverlight requires, so they must be present in your XAML. They’re always the same, and you won’t have any need to change them.

As you can see, for various elements in your shell, you can refer to brushes that have been defined in the theme’s resource dictionary, simply by specifying it as a static resource binding, using the syntax ElementName={StaticResource BrushName}.

Listing 10-7. CentralShell.xaml File’s Initial Contents

XAML:

File: Central.ExtensionsCentral.Extensions.ClientPresentationSehllsCentralCentralShell.xaml

<UserControl x:Class="Central.Extensions.Presentation.Shells.CentralShell"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    >
    <Grid Background="{StaticResource NavShellBackgroundBrush}">

    </Grid>
</UserControl>
The Code-Behind File

The CentralShell class inherits from UserControl. The only method in the class is the constructor, which calls InitializeComponent. Most of the time, you won’t need to add any code to this file.

Common Project’s Elements

The Shell template also adds a Shells folder to the Common project’s Metadata folder, as you can see in Figure 10-25. Only a single file gets added to the Shells folder for our shell. Based on the name we gave the shell, it’s called CentralShell.lsml.

Images

Figure 10-25. Common project’s MetadataShells folder

The LSML File

The CentralShell.lsml file contains a model fragment that defines the shell’s details (see Listing 10-8). Two attributes are defined in it (see Table 10-9).

Images

Listing 10-8. CentralShell.lsml File’s XAML

LSML:

File: Central.Extensions.CommonMetadataShellsCentralShell.lsml

<?xml version="1.0" encoding="utf-8" ?>
<ModelFragment
  xmlns="http://schemas.microsoft.com/LightSwitch/2010/xaml/model"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  
  <Shell Name="CentralShell">
    <Shell.Attributes>
      <DisplayName Value="CentralShell"/>
      <Description Value="CentralShell description"/>
    </Shell.Attributes>
  </Shell>

</ModelFragment>

Microsoft’s Shell Extension Sample

Microsoft has made a simplified sample shell available for download in the MSDN Samples Gallery, at http://code.msdn.microsoft.com/LightSwitch-Shell-1869646f.

Understanding Screen Template Extensions

LightSwitch’s built-in templates make it easy to implement various commonly required data display and maintenance screens, but in some situations, the built-in templates don’t do quite what you need them to do. A screen template extension allows you to create (and share) templates that have common control layout patterns and are exactly suited to your particular needs.

The attributes and interfaces required by the screen template classes are found in the Microsoft.LightSwitch.Designers.ScreenTemplates.Model namespace.

Creating a Screen Template Extension

There are a few simple steps required to create a screen template extension:

  1. Create an extension library, as described earlier in the chapter (or you can add to an existing extension library).
  2. Right-click the LSPKG project (Central.Extensions.lspkg)
  3. Select Add Images New Item.
  4. Click the Screen Template option, shown in Figure 10-26.
  5. Provide a name for the screen template (we’ll call it CentralScreen).
  6. Click Add.
  7. The template adds various folders and files (discussed later in this section).The code that’s necessary to implement the required interfaces is also provided by the template (we’ll examine this next).
  8. Replace the default images with images that are appropriate for your screen.
  9. Modify the display name and description, along with any other property values that need to be changed.
  10. Add the code required to the supplied Generate method, to add the screen template elements.
Images

Figure 10-26. Adding a new screen template extension item

Using Screen Template Extension Attributes

Two attributes must be applied to any class that defines a screen template, for it to be recognized by LightSwitch: the Export attribute and the Template attribute (see Table 10-10).

Images

Listing 10-9 shows these attributes being used in code, to decorate the class that defines a screen template.

Listing 10-9. IScreenTemplate Attributes Being Used in Code

VB:

File: N/A

Friend Const TemplateId As String = "Central.Extensions:CentralScreen"

<Export(GetType(IScreenTemplateFactory))>
<Template(CentralScreen.TemplateId)>
Friend Class CentralScreenFactory
    Implements IScreenTemplateFactory

    'implementation code goes here
End Class

C#:

File: N/A

internal const string TemplateId = "Central.Extensions:CentralScreen";

[Export(typeof(IScreenTemplateFactory))]
[Template(CentralScreen.TemplateId)]
internal class CentralScreenFactory : IScreenTemplateFactory
{

    //implementation code goes here
}

Using Screen Template Interfaces

Two classes are required to define a screen template extension. One must implement the IScreenTemplate interface, and the other must implement the IScreenTemplateFactory interface.

IScreenTemplate Interface

The IScreenTemplate interface consists of eight properties and one method, listed in Table 10-11.

Images

Images

Table 10-12 shows the available values for RootDataSourceType, which are also found in the Microsoft.LightSwitch.Designers.ScreenTemplates.Model namespace.

Images

IScreenTemplateFactory Interface

The IScreenTemplateFactory interface consists of a single method, CreateScreenTemplate, which simply returns an instance of the screen template class (in our example, the CentralScreen class).

Screen Template Extension Implementation

A common requirement is to have a screen that you can use to both add and edit entities. With this, you would be able to replace the two separate screen templates that come with LightSwitch with just one. By doing this, you could encapsulate all of the code changes that you might need to write over and over, in just one screen template.

The following paragraphs assume that we’ve called our screen template CentralScreen.

Design Project’s Elements

When we add a screen template, using the Extensibility Toolkit’s Screen Template item, a ScreenTemplates folder is added to the Design project, and a ScreenTemplateImages folder is added to the project’s Resources folder for us, as shown in Figure 10-27.

We recommend creating a separate folder for each screen template in the ScreenTemplateImages folder and moving the files created by the extension template into it. You don’t have to do this, but it helps keep the project more organized. There’s no need to create a subfolder for each screen template in the ScreenTemplates folder, because there’s only one file added per screen template. But you could if you really wanted to.

Images

Figure 10-27. Design project’s ScreenTemplateImages folder and ScreenTemplates folder

The Image Files

Two default image files, CentralScreenLarge.png (245178) and CentralScreenSmall.png (2424), are added to the project for you. These represent the images that will be displayed for the template in the Add New Screen Wizard.

The small image is used in Select a Screen Template section, shown at the left of Figure 10-28. The large image is displayed for the selected screen template, shown in the center of Figure 10-28.

You’ll need to replace the default images with images that show the user what your screen template looks like.

Images

Figure 10-28. Screen template images in the Add New Screen Wizard

The Class File

When it’s created by the template, the CentralScreen file will contain implementations for both the IScreenTemplate (CentralScreen class) and IScreenTemplateFactory (CentralScreenFactory class) that we discussed earlier (see Listing 10-10). Because we moved the files for the shell into their own folder, we also had to make a small change to the ShellUri property’s value to reflect this folder change.

Imported Namespaces

Out of the nine namespaces that are listed in the Import/Using statements, only two (three for C#, if you include System) are required (the rest of them can safely be removed). The System.ComponentModel.Composition namespace is required for the Export attribute, and the Microsoft.LightSwitch.Designers.ScreenTemplates.Model namespace is required for the IScreenTemplate and IScreenTemplateFactory interfaces.

CentralScreen Class

The CentralScreen class contains the IScreenTemplate’s implementation code that we discussed earlier (see Listing 10-10). Most of the actual code for a screen template is found in the Generate method. This method can be used to add any data, code, or controls required for screens that are based on the screen template.

You can modify the template’s hierarchy of content items and create additional elements by using storage model classes such as ContentItem and all of its related classes. Generating a screen content tree can consist of any combination the following:

  • Adding a content item for the root data of a screen
  • Specifying a specific control to use for a content item
  • Expanding the children of a content item
  • Setting control property values
  • Setting the display name for any content items or screen members
  • Setting a screen’s data member properties
  • Adding screen members
  • Displaying the selected item of a collection
  • Adding group controls
  • Accessing related collections
  • Adding query parameters
  • Adding an entity field
  • Adding code to the screen

Images Caution  Remember that if you’ve changed the folder structure, as we have, you also need to update the ImageProvider code that refers to the elements that have been moved.

CentralScreenFactory Class

The CentralScreen class contains the IScreenTemplateFactory’s implementation code as well (see Listing 10-10). The only method in the class is the CreateScreenTemplate method, which simply returns a new instance of the CentralScreen class.

Listing 10-10. CentralScreen’s Code

VB:

File: Central.Extensions.DesignScreenTemplatesCentralScreen.vb

Imports System.ComponentModel.Composition

Imports Microsoft.LightSwitch.Designers.ScreenTemplates.Model

Namespace ScreenTemplates

    Friend Class CentralScreen
        Implements IScreenTemplate

        Friend Const TemplateId As String = "Central.Extensions:CentralScreen"

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

        Public ReadOnly Property DisplayName As String _
        Implements IScreenTemplateMetadata.DisplayName
            Get
                Return "CentralScreen"
            End Get
        End Property

        Public ReadOnly Property Description As String _
        Implements IScreenTemplateMetadata.Description
            Get
                Return "CentralScreen description"
            End Get
        End Property

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

        Public ReadOnly Property PreviewImage As Uri _
        Implements IScreenTemplateMetadata.PreviewImage
            Get
                'this is a modified version of what appears in the file
                'created by the template
                Dim uriString = String.Format("{0}{1}{2}"Images
                    , "/Central.Extensions.Design;"Images
                    , "component/Resources/ScreenTemplateImages/Central/"Images
                    , "CentralScreenLarge.png"Images
                    )
                Return New Uri(uriString, UriKind.Relative)
            End Get
        End Property

        Public ReadOnly Property SmallIcon As Uri _
        Implements IScreenTemplateMetadata.SmallIcon
            Get
                'this is a modified version of what appears in the file
                'created by the template
                Dim uriString = String.Format("{0}{1}{2}"Images
                    , "/Central.Extensions.Design;"Images
                    , "component/Resources/ScreenTemplateImages/Central/"Images
                    , "CentralScreenSmall.png"Images
                    )
                Return New Uri(uriString, 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 SupportsChildCollections As Boolean _
        Implements IScreenTemplateMetadata.SupportsChildCollections
            Get
                Return True
            End Get
        End Property

        Public Sub Generate(host As IScreenTemplateHost) _
        Implements IScreenTemplate.Generate

        End Sub

    End Class

    <Export(GetType(IScreenTemplateFactory))>
    <Template(CentralScreen.TemplateId)>
    Friend Class CentralScreenFactory
        Implements IScreenTemplateFactory

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

    End Class

End Namespace

C#:

File: Central.Extensions.DesignScreenTemplatesCentralScreen.cs

using System.ComponentModel.Composition;

using Microsoft.LightSwitch.Designers.ScreenTemplates.Model;

namespace ScreenTemplates
{
    internal class CentralScreen : IScreenTemplate
    {
        internal const string TemplateId = "Central.Extensions:CentralScreen";

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

        public string DisplayName
        {
            get
            {
                return "CentralScreen";
            }
        }

        public string Description
        {
            get
            {
                return "CentralScreen description";
            }
        }

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

        public Uri PreviewImage
        {
            get
            {
                //this is a modified version of what appears in the file
                //created by the template
                var uriString = string.Format("{0}{1}{2}”;Images
                   , "/Central.Extensions.Design;”Images
                   , "component/Resources/ScreenTemplateImages/Central/";Images
                   , "CentralScreenLarge.png"Images
                   );
                return new Uri(uriString, UriKind.Relative);
            }
        }

        public Uri SmallIcon
        {
            get
            {
                //this is a modified version of what appears in the file
                //created by the template
                var uriString = string.Format("{0}{1}{2}";Images
                   , "/Central.Extensions.Design;";Images
                   , "component/Resources/ScreenTemplateImages/Central/";Images
                   , "CentralScreenSmall.png"Images
                   );
                return new Uri(uriString, UriKind.Relative);
            }
        }

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

        public bool SupportsChildCollections
        {
            get
            {
                return true;
            }
        }

        public void Generate(IScreenTemplateHost host)
        {

        }
    }

    [Export(typeof(IScreenTemplateFactory)), Template(CentralScreen.TemplateId)]
    internal class CentralScreenFactory : IScreenTemplateFactory
    {
        public IScreenTemplate CreateScreenTemplate()
        {
            return new CentralScreen();
        }
    }
}

images Tip  Remember that if you change the name of either of the image files, you need to change any code that references them as well.

Microsoft’s Screen Template Sample

Microsoft’s screen template sample can be found at http://code.msdn.microsoft.com/LightSwitch-Screen-1b414903.

Understanding Control Extensions

Control extensions are created by combining Silverlight user controls with additional attributes to allow them to be integrated into LightSwitch. So there’s no need to manually select Custom Control as the control type, find the assembly that contains the custom control, and then select and bind it each time you want to use that particular custom control. Using control extensions make custom controls as easy to select as any of the controls that LightSwitch provides out-of-the-box.

Several types of control extensions can be created, as shown in Table 10-13.

Images

From their name, custom controls may sound like they just deliver extra user interface/presentation layer capabilities. But they can provide packages of much broader functionality. Custom controls can be thought of as little applications within your bigger LightSwitch application. For example, a reporting control might not just display reports, it may also generate them. An analysis control might not just display a cross tab view of data, it might also provide filtering and aggregation capabilities.

The attributes and interfaces required by the control extension classes are found in the Microsoft.LightSwitch.Presentation namespace.

Creating a Control Extension

There are a few simple steps required to create a control extension:

  1. Create an extension library, as described earlier in the chapter (or you can add to an existing extension library).
  2. Right-click the LSPKG project (Central.Extensions.lspkg)
  3. Select Add Images New Item.
  4. Click the Control option, shown in Figure 10-29.
  5. Provide a name for the control (we’ll call it CentralControl).
  6. Click Add
  7. The various projects, folders, and files (discussed later in this section) are created
  8. Provide whatever code is necessary for the required interface implementations, and the XAML for the visual representation.
Images

Figure 10-29. Adding a new control extension item

Using Control Extension Attributes

Several attributes must be applied to any class that defines a control, for it to be recognized by LightSwitch (see Table 10-14).

Images

Images

Listing 10-11 shows these attributes being used in code.

Listing 10-11. Control Attributes Being Used in Code

VB:

File: N/A

'in the Client project
<Export(GetType(IControlFactory))>
<ControlFactory("Central.Extensions:CentralControl")>
Friend Class CentralControlFactory
    Implements IControlFactory

    'implementation code goes here
End Class

'in the Client.Design and Design projects
<Export(GetType(IResourceProvider))>
<ResourceProvider("Central.Extensions.CentralControl")>
Friend Class CentralControlImageProvider
    Implements IResourceProvider

    'implementation code goes here
End Class

C#:

File: N/A

//in the Client project
[Export(typeof(IControlFactory)), ControlFactory("Central.Extensions:CentralControl")]
internal class CentralControlFactory : IControlFactory
{

    //implementation code goes here
}

//in the Client.Design and Design projects
[Export(typeof(IResourceProvider)), ResourceProvider("Central.Extensions.CentralControl")]
internal class CentralControlImageProvider : IResourceProvider
{

    //implementation code goes here
}

Using Control Extension Interfaces

A class that defines a control item must implement two interfaces, the IControlFactory interface and the IResourceProvider interface.

IControlFactory Interface

The IControlFactory interface must be implemented in both the Client project and the Client.Design project. It consists of one property and one method (see Table 10-15).

Images

IResourceProvider Interface

The IResourceProvider interface consists of just a single method, GetResource, which returns a BitmapImage from a URI that’s constructed using the name of the image file path and the assembly that contains the image.

Control Extension Implementation

When you define a control extension, you use a Silverlight control to display the data. You can also include custom design-time properties that you can later refer to in code.

Client Project’s Elements

Just as adding a theme extension added a Themes folder to the Client project’s Presentation folder, adding a control extension will add a Controls folder to it as well. Three files get added to the Controls folder.

We recommend creating a separate folder for each control in the Controls folder and moving the files created by the template into it. You don’t have to do this, but it helps keep the project more organized. For our example control, we’ll create a folder called CentralControl and move the files into that folder, as shown in Figure 10-30.

Images

Figure 10-30. Client Project’s ControlImages Folder

Images Caution  Remember that if you’ve changed the folder structure, as we have, you also need to update any code that refers to the elements that have been moved.

The XAML File

The CentralControl.xaml file contains the XAML definitions that represent the control itself (see Listing 10-12). By default, it simply contains a TextBox, with a two-way binding to the StringValue control’s property. You need to replace this with the XAML required to display your extension’s control.

Listing 10-12. Default XAML Representation of the Control

XML:

File: Central.Extensions.ClientPresentationControlsCentralControlCentralControl.xaml

<UserControl x:Class="Central.Extensions.Presentation.Controls.CentralControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    >
    <TextBox Text="{Binding StringValue, Mode=TwoWay}"/>
</UserControl>

The class declaration and the two namespace declarations will be added for you. There’s no need to change either of the xmlns definitions, and in fact if you do change them in any way, your control will no longer work.

If you change the namespace where the control’s code is found, or the name of the control itself, you’ll have to change the class definition to match.

The Code-Behind File

There are three sections to take note of in the XAML’s code-behind file.

Imported Namespaces

Out of the sixteen namespaces that are listed in the Import/Using statements, only three (four for C#, if you include System) are required; the rest of them can safely be removed. The System.ComponentModel.Composition namespace is required for the Export attribute, the System.Windows.Markup namespace is required for XamlReader, and Microsoft.LightSwitch.Presentation is required for IControlFactory and IContentItem.

CentralControl Class

The control’s class inherits from UserControl. The only method in the class is the constructor, which calls InitializeComponent. As noted earlier, the name of this class must match the x:Class name in the XAML file.

CentralControlFactory Class

Curiously, the generated code in the XAML file’s code-behind file contains not only the usual code that you’d find for a UserControl, but also the actual control’s IControlFactory implementation (see Listing 10-13). This class contains the XAML definition for the control’s DataTemplate, as well as an optional display mode DataTemplate.

We advise you to extract this class out into its own file, to give the class a bit more visibility, making it easier to find when you want to make changes to the data template definitions. This is especially helpful when using the copy/paste method of creating extensions.

Listing 10-13. CentralControl’s Code

VB:

File: CentralExtensions.ClientPresentationControlsCentralControlCentralControl.vb

Imports System.ComponentModel.Composition
Imports System.Windows.Markup

Imports Microsoft.LightSwitch.Presentation

Namespace Presentation.Controls

    Partial Public Class CentralControl
        Inherits UserControl

        Public Sub New()
            InitializeComponent()
        End Sub

    End Class

    'the template put this class in this file, but you can move it
    '(and the namespaces above) to a file of its own
    'as we discussed, it really doesn’t belong in here
    <Export(GetType(IControlFactory))>
    <ControlFactory("Central.Extensions:CentralControl")>
    Friend Class CentralControlFactory
        Implements IControlFactory

        'Constants
        Private Const ControlTemplate As String =Images
            "<DataTemplate" &Images
            " xmlns="'http://schemas.microsoft.com/winfx/2006/xaml/presentation'" &Images
            " xmlns:x="'http://schemas.microsoft.com/winfx/2006/xaml'" &Images
            " xmlns:ctl="'clr-namespace:Central.Extensions.Presentation.Controls;" &Images
            "assembly=Central.Extensions.Client'>" &Images
            "<ctl:CentralControl/>" &Images
            "</DataTemplate>"

        'IControlFactory Members
        Private cachedDataTemplate As DataTemplate
        Public ReadOnly Property DataTemplate As DataTemplateImages
        Implements IControlFactory.DataTemplate
            Get
                If Me.cachedDataTemplate Is NothingImages
                Then
                    Me.cachedDataTemplate = TryCast(Images
                          XamlReader.Load(CentralControlFactory.ControlTemplate)Images
                        , DataTemplateImages
                        )
                End If

                Return Me.cachedDataTemplate
            End Get
        End Property

        Public Function GetDisplayModeDataTemplate(Images
              ByVal contentItem As IContentItemImages
            ) As DataTemplateImages
        Implements IControlFactory.GetDisplayModeDataTemplate
            Return Nothing
        End Function

    End Class

End Namespace

C#:

File: CentralExtensions.ClientPresentationControlsCentralControlCentralControl.cs

using System;
using System.ComponentModel.Composition;
using System.Windows.Markup;

using Microsoft.LightSwitch.Presentation;

namespace Presentation.Controls
{
    public partial class CentralControl : UserControl
    {
        public CentralControl()
        {
            InitializeComponent();
        }
    }

    //the template put this class in this file, but you can move it
    //(and the namespaces above) to a file of its own
    //as we discussed, it really doesn’t belong in here
    [Export(typeof(IControlFactory)), ControlFactory("Central.Extensions:CentralControl")]
    internal class CentralControlFactory : IControlFactory
    {
        //Constants
        private const string ControlTemplate = "<DataTemplate" +Images
            " xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"" +Images
            " xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"" +Images
            " xmlns:ctl="clr-namespace:Central.Extensions.Presentation.Controls;" +Images
            "assembly=Central.Extensions.Client">" + "<ctl:CentralControl/>" +Images
            "</DataTemplate>";

        //IControlFactory Members
        private DataTemplate cachedDataTemplate;
        public DataTemplate DataTemplate
        {
            get
            {
                if (this.cachedDataTemplate == null)
                {
                    this.cachedDataTemplate =XamlReader.Load(Images
                          CentralControlFactory.ControlTemplateImages
                        ) as DataTemplate;
                }
                return this.cachedDataTemplate;
            }
        }

        public DataTemplate GetDisplayModeDataTemplate(IContentItem contentItem)
        {
            return null;
        }
    }
}
Client.Design Project’s Elements

A ResourcesControlImages folder, shown in Figure 10-31, also will have been added to the Client.Design project by the template. This is another case where we’d suggest adding a folder for each of the control extensions that you add, if there’s more than one, or if you plan on adding more control extensions later.

Two files get added to the ControlImages folder.

Images

Figure 10-31. ControlImages folder added to Presentation folder

The Image File

By default, the CentralControl.png file will be a generic image (a 3D green sphere). You need to replace this with the image that you want to display for your control.

The file should be:

  • A PNG, BMP, or JPG (but not a GIF, as Silverlight doesn’t support GIF files)
  • 32 × 32 pixels
The Image Provider Class

The CentralControlImageProvider file contains the IResourceProvider implementation, as shown in Listing 10-14.

Listing 10-14. Control Image Provider Code

VB:

File: ResourcesControlImagesCentralControlCentralControlImageProvider.vb

Imports System
Imports System.ComponentModel.Composition
Imports System.Globalization
Imports System.Windows.Media.Imaging

Imports Microsoft.LightSwitch.BaseServices.ResourceService

Namespace Resources

    <Export(GetType(IResourceProvider))>
    <ResourceProvider("Blank.Extension.CentralControl")>
    Friend Class CentralControlImageProvider
        Implements IResourceProvider

        Public Function GetResource(Images
              ByVal resourceId As StringImages
            , ByVal cultureInfo As CultureInfoImages
            ) As Object _
        Implements IResourceProvider.GetResource
            Return New BitmapImage(New Uri(Images
                "/Blank.Extension.Client.Design;component/Resources/ControlImages/Images
                    CentralControl.png"Images
                , UriKind.Relative)Images
                )
        End Function

    End Class

End Namespace

C#:

File: ResourcesControlImagesCentralControlCentralControlImageProvider.cs

using System;
using System.ComponentModel.Composition;
using System.Globalization;
using System.Windows.Media.Imaging;

using Microsoft.LightSwitch.BaseServices.ResourceService;

namespace Resources
{
    [Export(typeof(IResourceProvider)), ResourceProvider("Blank.Extension.CentralControl")]
    internal class CentralControlImageProvider : IResourceProvider
    {
        public object GetResource(string resourceId, CultureInfo cultureInfo)
        {
            return new BitmapImage(new Uri(Images
                "/Blank.Extension.Client.Design;component/Resources/ControlImages/Images
                    CentralControl.png"Images
                , UriKind.Relative)Images
                );
        }
    }
}

Images Caution  Remember that if you’ve changed the folder structure, as we have, you also need to update any code that refers to the elements that have been moved.

Common Project’s Elements

The template will have added a Controls folder to the Common project’s Metadata folder, as shown in Figure 10-32. Only a single file is added to this folder for each control extension, so there’s no need for separate folders.

Images

Figure 10-32. Common Project’s Controls Folder

The LSML File

The CentralControl.lsml file contains a model fragment that defines the control’s details, as shown in Listing 10-15. This includes several attributes and properties. By default there are four (see Table 10-16).

Images

Listing 10-15. CentralControl.lsml File’s XAML

LSML:

File: Central.Extensions.CommonMetadataControlsCentralControl.lsml

<?xml version="1.0" encoding="utf-8" ?>
<ModelFragment
  xmlns="http://schemas.microsoft.com/LightSwitch/2010/xaml/model"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  
  <Control Name="CentralControl"
    SupportedContentItemKind="Value"
    DesignerImageResource="Central.Extensions.CentralControl::ControlImage">
    <Control.Attributes>
      <DisplayName Value="CentralControl" />
    </Control.Attributes>

    <Control.SupportedDataTypes>
      <SupportedDataType DataType=":String"/>
    </Control.SupportedDataTypes>
  </Control>

</ModelFragment>

Control Extension Element Mapping

The LightSwitch controls used in its shell and in its screens are all based on Silverlight controls. Table

10-17 contains the mappings of the LightSwitch control elements to their underlying Silverlight controls.

Images

Images

Microsoft’s Control Extension Samples

Microsoft has provided the following control extension samples (usually with a link to a walk-through):

Understanding Business Type Extensions

Business types allow you wrap a base data type in what’s called a semantic type. This enables you to present data in a way that’s most appropriate for your application, adding extra validation and display capabilities in LightSwitch, while continuing to store the actual data as its underlying data type in the database.

The attributes and interfaces required for a business type extension are found in the Microsoft.LightSwitch.Presentation namespace.

Out-of-the-box, LightSwitch comes with several predefined business types, listed in Table 10-18. For those business types to be active, the Microsoft LightSwitch Extensions extension must be activated for the project (it’s active by default).

Images

You can think of business types as an extra layer of validation and formatting that sits on top of a normal database type. This allows LightSwitch’s data models to be even smarter than they would be if they could work with only the base data types.

Table 10-19 shows some examples of what a business type could be used for.

Images

Images

Using a business type makes it easy to ensure that only valid data is entered, while enabling the work that went into creating the validation code, for example, to be done just once, rather than needing to be duplicated in any new application. So business types make it easy to share and reuse code that may have taken quite some time and effort to get working correctly, saving you both time and money. For example, an IT department could do all the hard work and then simply make the business type available to be installed and used by various other departments, knowing that the data will be handled correctly. They could even make its use compulsory.

Without a business type, each department could well end up creating their own implementations, wasting time re-creating the wheel, as they say, and possibly introducing bugs into the application that will also take time to track down and fix. So you can view business types as both a productivity tool and a data governance tool.

Creating a Business Type Extension

There are a few simple steps required to create a business type extension:

  1. Create an extension library, as described earlier in the chapter (or you can add to an existing extension library).
  2. Right-click the LSPKG project (Central.Extensions.lspkg)
  3. Select Add Images New Item.
  4. Click the Business Type option, shown in Figure 10-33.
  5. Provide a name for the business type (we’ll call it CentralType).
  6. Click Add
  7. Provide whatever code or XAML is necessary for the required interface implementations (also discussed in more detail, later in this section).
Images

Figure 10-33. Adding a new business type extension item

Using Business Type Extension Attributes

Several attributes are used by classes that define a business type extension, in order for its elements to be recognized by LightSwitch. Two attributes are used in the Client project: Export and ControlFactory. Both the Client.Design project and the Design project also use two attributes: Export and ResourceProvider.

Export Attribute

The Export attribute supplies the contracts that LightSwitch requires for an extension to identify itself as a business type extension. These are IControlFactory and IResourceProvider (see Listing 10-16).

ControlFactory Attribute

The ControlFactory attribute then provides further information about the business type’s control. The information required is a String Id value, in the form of ExtensionLibraryName:ControlName.

Listing 10-16. Business Type Attributes Being Used in Code

VB:

File: N/A

'in the Client project
<Export(GetType(IControlFactory))>
<ControlFactory("Central.Extensions:CentralTypeControl")>
Friend Class CentralTypeControlFactory
    Implements IControlFactory

    'implementation code goes here
End Class

'in the Client.Design and Design projects
<Export(GetType(IResourceProvider))>
<ResourceProvider("Central.Extensions.CentralTypeControl")>
Friend Class CentralTypeControlImageProvider
    Implements IResourceProvider

    'implementation code goes here
End Class

C#:

File: N/A

//in the Client project
[Export(typeof(IControlFactory))]
[ControlFactory("Central.Extensions:CentralTypeControl")]
internal class CentralTypeControlFactory : IControlFactory
{

    //implementation code goes here
}

//in the Client.Design and Design projects
[Export(typeof(IResourceProvider))]
internal class CentralTypeControlImageProvider : IResourceProvider
{

    //implementation code goes here
}

Using Business Type Extension Interfaces

A class that defines a business type extension must implement two interfaces: IControlFactory and IResourceProvider.

IControlFactory Interface

The IControlFactory interface must be implemented in both the Client project and the Client.Design project. As we noted in the control extension section, it consists of one property and one method, listed in Table 10-20.

Images

IResourceProvider Interface

Also as noted in the control extensions section, the IResourceProvider interface consists of just a single method, GetResource, which returns a BitmapImage from a URI that’s constructed using the name of the image file path, and the assembly that contains the image.

Business Type Extension Implementation

When you define a business type, you can add custom design-time properties that you can later refer to in code. A business type can also have a control associated with it (and in most cases, it does), so some of the implementation code is very similar to a control extension’s implementation code. But we’ll still include all of the implementation details in this section, so that each extension section is self-contained.

Client Project’s Elements

Just as adding a control extension added a Controls folder to the Client project’s Presentation folder, adding a business type extension will also add a Controls folder to it if it doesn’t already exist, as shown in Figure 10-34. Three files get added to the Controls folder. Once again, we recommend creating a separate folder for each business type and moving the files that get created into it.

Images

Figure 10-34. Client Project’s Controls Folder

Images Caution  Remember that if you’ve changed the folder structure, as we have, you also need to update any code that refers to the elements that have been moved.

The XAML File

The CentralTypeControl.xaml file contains the XAML that represents the business type’s control itself, as you can see in Listing 10-17. By default, it simply contains a TextBox, with a two-way binding to the StringValue control’s property. You need to replace this with the XAML required to display your intended control.

Listing 10-17. Initial XAML Representation of the Business Type’s Control

XML:

File: Central.Extensions.ClientPresentationControlsCentralTypeCentralTypeControl.xaml

<UserControl x:Class="Central.Extensions.Presentation.Controls.CentralTypeControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    >
    <TextBox Text="{Binding StringValue, Mode=TwoWay}"/>
</UserControl>

The class declaration and the two namespace declarations will be added for you. There’s no need to change either of the xmlns definitions, and in fact if you do change them in any way, your control will no longer work.

The Code-Behind File

There are three sections to take note of in the XAML’s code-behind file.

Imported Namespaces

Out of the sixteen namespaces that are listed in the Import/Using statements, only three (four for C#, if you include System) are required (the rest of them can safely be removed). The System.ComponentModel.Composition namespace is required for the Export attribute, the System.Windows.Markup namespace is required for XamlReader, and the Microsoft.LightSwitch.Presentation namespace is required for IControlFactory and IContentItem.

CentralTypeControl Class

The control’s class inherits from UserControl. The only method in the class is the constructor, which calls InitializeComponent.

CentralTypeControlFactory Class

As with the CentralControlFactory class in the control extension, the generated code in the XAML file’s code-behind file contains not only the usual code that you’d find for a UserControl, but also the actual business type control’s IControlFactory implementation (see Listing 10-18). This class contains the XAML definition for the control’s DataTemplate, as well as an optional display mode DataTemplate.

We advise you to extract this class out into its own file, to give the class a bit more visibility, making it easier to find when you want to make changes to the data template definitions. This is especially helpful when using the copy/paste method of creating extensions.

Listing 10-18. CentralTypeControl’s Code

VB:

File: CentralExtensions.ClientPresentationControlsCentralTypeCentralTypeControl.vb

Imports System.ComponentModel.Composition
Imports System.Windows.Markup

Imports Microsoft.LightSwitch.Presentation

Namespace Presentation.Controls

    Partial Public Class CentralTypeControl
        Inherits UserControl

        Public Sub New()
            InitializeComponent()
        End Sub

    End Class

    
    'the template put this class in this file, but you can move it
    '(and the namespaces above) to a file of its own
    'as we discussed, it really doesn’t belong in here

    <Export(GetType(IControlFactory))>
    <ControlFactory("Central.Extensions:CentralTypeControl")>
    Friend Class CentralTypeControlFactory
        Implements IControlFactory

        'Constants
        Private Const ControlTemplate As String =Images
            "<DataTemplate" &Images
            " xmlns="'http://schemas.microsoft.com/winfx/2006/xaml/presentation'" &Images
            " xmlns:x="'http://schemas.microsoft.com/winfx/2006/xaml'" &Images
            " xmlns:ctl="'clr-namespace:Central.Extensions.Presentation.Controls;" &Images
            "assembly=Central.Extensions.Client'>" &Images
            "<ctl:CentralTypeControl/>" &Images
            "</DataTemplate>"

        'IControlFactory Members
        Private cachedDataTemplate As DataTemplate
        Public ReadOnly Property DataTemplate As DataTemplateImages
        Implements IControlFactory.DataTemplate
            Get
                If Me.cachedDataTemplate Is NothingImages
                Then
                    Me.cachedDataTemplate = TryCast(Images
                          XamlReader.Load(CentralTypeControlFactory.ControlTemplate)Images
                        , DataTemplateImages
                        )
                End If

                Return Me.cachedDataTemplate
            End Get
        End Property

        Public Function GetDisplayModeDataTemplate(Images
              ByVal contentItem As IContentItemImages
            ) As DataTemplateImages
        Implements IControlFactory.GetDisplayModeDataTemplate
            Return Nothing
        End Function

    End Class

End Namespace

C#:

File: CentralExtensions.ClientPresentationControlsCentralControlCentralTypeControl.cs

using System;
using System.ComponentModel.Composition;
using System.Windows.Markup;

using Microsoft.LightSwitch.Presentation;

namespace Presentation.Controls
{
    public partial class CentralTypeControl : UserControl
    {
        public CentralTypeControl()
        {
            InitializeComponent();
        }
    }

    //the template put this class in this file, but you can move it
    //(and the namespaces above) to a file of its own
    //as we discussed, it really doesn’t belong in here
    [Export(typeof(IControlFactory)), ControlFactory("Central.Extensions:CentralTypeControl")]
    internal class CentralTypeControlFactory : IControlFactory
    {
        //Constants
        private const string ControlTemplate = "<DataTemplate" +Images
            " xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'" +Images
            " xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'" +Images
            " xmlns:ctl='clr-namespace:Central.Extensions.Presentation.Controls;" +Images
            "assembly=Central.Extensions.Client'>" +Images
            "<ctl:CentralTypeControl/>" +Images
            "</DataTemplate>";

        //IControlFactory Members
        private DataTemplate cachedDataTemplate;
        public DataTemplate DataTemplate
        {
            get
            {
                if (this.cachedDataTemplate == null)
                {
                    this.cachedDataTemplate = XamlReader.Load(Images
                          CentralTypeControlFactory.ControlTemplateImages
                        ) as DataTemplate;
                }
                return this.cachedDataTemplate;
            }
        }

        public DataTemplate GetDisplayModeDataTemplate(IContentItem contentItem)
        {
            return null;
        }
    }
}
Client.Design Project’s Elements

A ResourcesControlImages folder (see Figure 10-35) will have been also added to the Client.Design project by the template. Two files get added to the ControlImages folder. This is another case where we’d suggest adding a folder for each of the control extension that you add, if there’s more than one, or if you plan on adding more business type extensions later.

Images

Figure 10-35. Client.Design project’s ControlImages folder

The Image File

By default, the CentralTypeControl.png file will be a generic image (a 3D green sphere). You need to replace this with the image that you want to display for your control.

The file should be:

  • a PNG, BMP, or JPG (but not a GIF, as Silverlight doesn’t support GIF files)
  • 32 × 32 pixels
The Image Provider Class

The CentralTypeControlImageProvider file contains the IResourceProvider implementation (see Listing 10-19).

Listing 10-19. Business Type Control’s Image Provider Code

VB:

File: ResourcesControlImagesCentralTypeCentralTypeControlImageProvider.vb

Imports System
Imports System.ComponentModel.Composition
Imports System.Globalization
Imports System.Windows.Media.Imaging

Imports Microsoft.LightSwitch.BaseServices.ResourceService

Namespace Resources

    <Export(GetType(IResourceProvider))>
    <ResourceProvider("Blank.Extension.CentralTypeControl")>
    Friend Class CentralTypeControlImageProvider
        Implements IResourceProvider

        Public Function GetResource(Images
              ByVal resourceId As StringImages
            , ByVal cultureInfo As CultureInfoImages
            ) As Object _
        Implements IResourceProvider.GetResource
            Return New BitmapImage(New Uri(Images
                "/Blank.Extension.Client.Design;component/Resources/ControlImages/Images
                    CentralType/CentralType.png"Images
                , UriKind.Relative)Images
                )
        End Function

    End Class

End Namespace

C#:

File: ResourcesControlImagesCentralTypeCentralTypeControlImageProvider.cs

using System;
using System.ComponentModel.Composition;
using System.Globalization;
using System.Windows.Media.Imaging;

using Microsoft.LightSwitch.BaseServices.ResourceService;

namespace Resources
{
    [Export(typeof(IResourceProvider)), ResourceProvider("Blank.Extension.CentralTypeControl")]
    internal class CentralTypeControlImageProvider : IResourceProvider
    {
        public object GetResource(string resourceId, CultureInfo cultureInfo)
        {
            return new BitmapImage(new Uri(Images
                "/Blank.Extension.Client.Design;component/Resources/ControlImages/Images
                    CentralType/CentralType.png"Images
                , UriKind.Relative)Images
                );
        }
    }
}

Images Caution  Remember that if you’ve changed the folder structure, as we have, you also need to update any code that refers to the elements that have been moved.

Common Project’s Elements

The Business Type template will have added a Controls folder and a Types folder to the Common project’s Metadata folder, as shown in Figure 10-36. Only a single file is added to these folders for each business type extension, so there’s no need for separate folders.

Images

Figure 10-36. Common project’s Controls and Types folders

The LSML File

The LSML file contains some XML, which defines a model fragment, shown in Listing 10-20. This model fragment specifies various attributes and properties for the business type. By default there are two (see Table 10-21).

Images

Images Tip  A single colon (:) can often be used as a shortcut for Microsoft.LightSwitch:.

Listing 10-20. Default Business Type Model Fragment

LSML:

File: Central.Extensions.CommonMetadataTypesCentralType.lsml

<?xml version="1.0" encoding="utf-8" ?>

<ModelFragment
  xmlns="http://schemas.microsoft.com/LightSwitch/2010/xaml/model"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  
  <SemanticType Name="CentralType"
    UnderlyingType=":String">
    <SemanticType.Attributes>
      <DisplayName Value="CentralType" />
    </SemanticType.Attributes>
  </SemanticType>

  <DefaultViewMapping
    ContentItemKind="Value"
    DataType="CentralType"
    View="CentralTypeControl"/>

</ModelFragment>
Editor and Viewer Controls

You can create multiple controls for your business type. An Editor and a Viewer are the most common.

Understanding Data Source Extensions

LightSwitch applications can natively connect to SQL Server databases, SharePoint lists, and WCF RIA Services. If you need to connect to some other type of data source, that’s where the extensibility features come in handy. A data source extension is essentially an adapter class (a domain service) that enables LightSwitch to work with data sources that it normally wouldn’t understand.

By using RIA Services as service layer, you can write code that connects with just about any external data source. LightSwitch then interfaces with the service layer, allowing the data to appear as standard LightSwitch data entities. After the data source extension has been written, connecting with external services is transparent for LightSwitch application developers who are consuming the data source.

Data source extensions work particularly well for in-house use. An IT department can build a RIA service around data from a particular legacy application and wrap it in a data source extension. This enables it to be shared for use in other LightSwitch applications. Data source extensions can also be included as companions to other extension types in the same extension library. For example, the DevExpress XtraReports control provides its own data source extension to enable report preview screens to communicate with the report server.

The classes that are required for a data source extension come predominantly from:

  • System.ServiceModel.DomainServices.Server
  • System.ComponentModel.DataAnnotations

Creating a Data Source Extension

There are a few simple steps required to create a data source extension:

  1. Create an extension library, as described earlier in the chapter (or you can add to an existing extension library).
  2. Right-click the LSPKG project (Central.Extensions.lspkg).
  3. Select Add Images New Item.
  4. Click the Data Source option, shown in Figure 10-37.
  5. Provide a name for the data source (we’ll call it CentralSource).
  6. Click Add.
  7. The various projects, folders, and files (discussed later in this section) are created.
  8. Provide whatever code or XAML is necessary for the required interface implementations (also discussed in more detail later in this section).
Images

Figure 10-37. Adding a new data source extension item

Data Source Extension Implementation

From the point of view of writing extensions, a data source extension is the simplest of all the extension types. There are no special attributes that LightSwitch requires to advertise its presence as an extension. And there are no interfaces that are required to be implemented.

A data source extension is simply a custom RIA service (you learned about creating and using RIA services in Chapter 7). If you know how to create a RIA service, you know how to create a data source extension.

LightSwitch uses the custom DomainService class that you write as a kind of in-memory data adapter, calling the instance directly from its data service implementation to perform query and submit operations.

Using this mechanism, you can create a DomainService class that exposes entity types and implements query, insert, update, and delete methods. LightSwitch infers a LightSwitch entity model based on the exposed entity types and infers an entity set based on the presence of a query decorated with the Query attribute (with IsDefault set to true). A primary-key property also has to be defined by decorating it with the Key attribute.

Server Project’s Elements

When we add a screen template, using the Extensibility Toolkit’s Data Source item, a DataSources folder is added to the Server project for us, as shown in Figure 10-38. Unlike several of the other extension item types, there’s no real need to create a subfolder for each data source in the DataSources folder, because only one file is added per data source. But again, you could if you really wanted to.

Images

Figure 10-38. Server project’s DataSources folder

The Class File

There are two sections to take note of in the CentralSource class file.

Imported Namespaces

Out of the five namespaces that are listed in the Import/Using statements, only one (two for C#, if you include System) is required, plus one that you’ll need when you start writing the code for the data source (the rest of them can safely be removed). The System.ServiceModel.DomainServices.Server is required for DomainService, and System.ComponentModel.DataAnnotations is required for the Key attribute.

CentralSource Class

The data source’s class inherits from DomainService. No other code is added to the class by the template, just a TODO comment that acts as a reminder that this is the place to create methods that contain the logic required for your data source.

Debugging Extensions

The Microsoft recommended way of debugging an extension is to use what’s called the experimental instance of Visual Studio:

  1. Set any breakpoints in your extension’s code.
  2. On the menu bar, select Debug Images Start Debugging (this opens the experimental instance.
  3. On the menu bar of the experimental instance, select Add Images New Project (or, you could open an existing project instead).
  4. In the New Project dialog box, select LightSwitch Application (either VB or C#).
  5. Give the project a name and click OK.
  6. In the Extensions tab of the project’s properties, enable the extension for the project.

Distributing Extensions

There are two methods that you can use to distribute your extension, depending on whether you want to make it available to the general public or just to people you know personally.

When you’re happy that your extension is behaving the way that you want it to, you should make sure that the solution configuration setting is set to Release, as shown in Figure 10-39. If you leave it set to Debug, you’ll be publishing debug symbols with your extension, and the download time for your users may also be longer than necessary.

Images

Figure 10-39. Solution configuration

If the solution configuration isn’t available on your Visual Studio toolbar, you can access it by clicking Build Images Configuration Manager to access the dialog box shown in Figure 10-40.

Images

Figure 10-40. Configuration Manager

Images Tip  Before distributing your extension, you should make sure that you’ve entered at least a name, description, and author in the VSIX project’s settings, as described earlier in the VSIX project section.

Sharing the Setup File

To share the setup file, follow these steps (replacing Central.Extensions with the name you gave your extension):

  1. In Windows Explorer, browse to the Central.Extensions.vsixinRelease folder.
  2. Right-click Central.Extensions.vsix
  3. Select Copy.
  4. Browse to a network share or some form of removable media (flash drive or CD/DVD).
  5. Select Paste.
  6. On the machine where you want to install the extension, open the VSIX file (click or double-click, as required).
  7. Select Install
  8. Follow the Extension Installer prompts.

Publishing to the Visual Studio Gallery

To publish your extension so that everyone can access it:

  1. In the Visual Studio Gallery web site, sign in (if you’re not already signed in).
  2. In Step 1: Extension Type, select Control and click Next. (You must select Control for a LightSwitch extension.)
  3. In Step 2: Upload, select I Would Like to Upload My Control.
  4. Browse to the Central.Extensions.vsixinRelease folder and select the VSIX file and click Next.
  5. In Step 3: Basic Information, information from the manifest has been entered for you, and LightSwitch has been selected as the Category for you. Set the following options:
    • Add tags that will help categorize your extension.
    • Choose a Cost Category (Free, Trial, or Paid).
    • Set Allow Discussions for your extension to True/False.
    • Enter the description for your extension (either manually, or using one of the provided templates).
    • Read and accept the Contribution Agreement.
    • Select the Create Contribution option (the extension has not yet been published).
    • When you’re happy with all of the information, click Publish.

Summary

There’s been a lot to learn in this chapter. First we explored why you might need an extension:

  • To enhance the look and feel of your applications
  • To enable more-advanced data entry scenarios
  • To get access to external sources data that LightSwitch doesn’t know how to communicate with natively

Then you examined the two ways of finding extensions, through either the Visual Studio Gallery web site or with the built-in Extension Manager. You also learned how to install them.

You looked briefly at some extensions made available by community members as well as the offerings of some third-party commercial vendors.

Further on in the chapter, you learned about:

  • How the LightSwitch 2011 Extensibility Toolkit makes creating extensions easier than ever before
  • How to create an your own extension library
  • The seven projects types that an extension is made up of (plus what extension type uses which project types)
  • The setup file (and how to set the manifest’s properties in the VSIX Manifest Designer)

We then gave you some background information to help you understand each of the six extension types:

  • Theme extensions
  • Shell extensions
  • Screen template extensions
  • Control extensions
  • Business type extensions
  • Data source extensions

Finally, we showed you how to debug your extensions, as well as how you can distribute them to other users.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.182.62