Friday, October 30, 2009

MEF in .NET 4.0/Visual Studio 2010 – Simple Example

The Managed Extensibility Framework (MEF) is a new library in .NET Framework 4.0 that helps in simplifying the design of extensible applications and components. If you are developing a .NET application (WinForms, WPF, Silverlight or ASP.Net) that supports plugins (independent libraries with different functionalities), then MEF is very handy.

Let us examine the basics of MEF through a very plain example application. I am building a WinForms showroom application which will display different vehicles. I have my own vehicles to display, and the application also supports vehicles from other vendors (aka plugins). All they need to do is to stick to my contract (aka implement the interface I give) while they develop their vehicles.

Let us first define the required contract. In Visual Studio 2010 (My version is Beta 2), create a new C# class library project and name it as Showroom.Contracts. Add an interface to it as below:
namespace Showroom.Contracts
{
    public interface IVehicle
    {
        string GetVehicleDetails();
    }
}

Now let us assume that we distribute this contract (interface library) to other vendors so that they can create vehicles that will fit in our showroom. To portray this scenario add another class library project named Vehicle.Hyundai. Add Showroom.Contracts project as a reference to this project as we need to implement the contract interface. This is going to be a plugin (extension or ComposablePart in MEF terminology) and hence we need to also add a reference to the MEF library System.ComponentModel.Composition. Add a class as shown below to this project:

namespace Vehicle.Hyundai
{
    using System.ComponentModel.Composition;
    using Showroom.Contracts;

    [Export(typeof(IVehicle))]
    public class HyundaiSonata : IVehicle
    {
        string IVehicle.GetVehicleDetails()
        {
            return "Hyundai Sonata";
        }
    }
}

Notice the Export attribute. This informs MEF that this is a plugin of type IVehicle. Now let us add one more similar class:

namespace Vehicle.Hyundai
{
    using System.ComponentModel.Composition;
    using Showroom.Contracts;

    [Export(typeof(IVehicle))]
    public class HyundaiSantro : IVehicle
    {
        string IVehicle.GetVehicleDetails()
        {
            return "Hyundai Santro!";
        }
    }
}

To portray one more vendor, add another class library project named Vehicle.Maruti and add a similar class to this as well:

namespace Vehicle.Maruti
{
    using System.ComponentModel.Composition;
    using Showroom.Contracts;

    [Export(typeof(IVehicle))]
    public class MarutiSwift : IVehicle
    {
        string IVehicle.GetVehicleDetails()
        {
            return "Maruti Swift";
        }
    }
}

Now that the contract and plugins based on these contracts are ready, let us build the showroom host or shell application to display these vehicles. Add a new WinForms project to the solution named Showroom.Shell. Add a project reference to Showroom.Contracts and reference to System.ComponentModel.Composition. Add a listbox to the form and name it as uxVehicles. This will display all the vehicles we have.

Remember we have our own vehicles to display in the showroom (besides vehicles from other vendors). Let us add a new class to the project:

namespace Showroom.Shell
{
    using System.ComponentModel.Composition;
    using Showroom.Contracts;

    [Export(typeof(IVehicle))]
    public class ShowroomVehicle1: IVehicle
    {
        string IVehicle.GetVehicleDetails()
        {
            return "Showroom Vehicle Normal";
        }
    }
}

And one more similar one:

namespace Showroom.Shell
{
    using System.ComponentModel.Composition;
    using Showroom.Contracts;

    [Export(typeof(IVehicle))]
    public class ShowroomVehicle2 : IVehicle
    {
        string IVehicle.GetVehicleDetails()
        {
            return "Showroom Vehicle Special";
        }
    }
}

Note that these are also decorated with Export attribute for MEF to pick them up later. Now go to the source code of Form1 to build the shell logic:

namespace Showroom.Shell
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.Composition;
    using System.ComponentModel.Composition.Hosting;
    using System.Reflection;
    using System.Windows.Forms;
    using Showroom.Contracts;

    public partial class Form1 : Form
    {
        [ImportMany(typeof(IVehicle))]
        public List<IVehicle> Vehicles { get; set; }

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            this.Vehicles = new List<IVehicle>();

            AggregateCatalog cat = new AggregateCatalog();
            cat.Catalogs.Add(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
            cat.Catalogs.Add(new DirectoryCatalog("Plugins"));

            CompositionContainer contnr = new CompositionContainer(cat);

            contnr.ComposeParts(this);

            foreach (IVehicle item in this.Vehicles)
            {
                uxVehicles.Items.Add(item.GetVehicleDetails());
            }
        }
    }
}

We have declared a property named Vehicles to contain all the vehicles we plan to display in our showroom. Notice the ‘ImportMany’ attribute. It tells MEF that this property need to be loaded using plugins of type ‘IVehicle’. We have used ‘ImportMany’ as there are more than one vehicle and will be using ‘Import’ instead if there is only one plugin.

MEF's core is comprised of a catalog and a CompositionContainer. A catalog is responsible for discovering extensions (plugins) and the container coordinates creation and satisfies dependencies. The AssemblyCatalog gathers plugins from an assembly. Here we have asked it to find all the plugins (classes with ‘Export’ attributes) from the currently executing assembly (Showroom.Shell). The DirectoryCatalog gathers plugins from a directory. Here we have asked the catalog to look in a directory named ‘Plugins’ for the assemblies containing classes that have ‘Export’ attribute. We have used AggregateCatalog to aggregate the tow different (Assembly and Directory) catalogs of plugins into one. The ComposeParts method of the CompositionContainer does all the magic by importing the required types from these plugins and loading them to the corresponding properties. Here in our code, the property ‘Vehicles’ will now be loaded with all the available vehicle plugins and we call their ‘GetVehicleDetails’ methods to add the results to a the listbox.

mefsample
Before running this application, copy the plugin assemblies (Vehicle.Hyundai.dll and Vehicle.Maruti.dll) to a folder named ‘Plugins’ under ..\bin\Debug\ folder of the Showroom.Shell project.

Download the complete sample (works in Visual Studio 2010 Beta 2) from here http://wayfarer.bizhat.com/techbites/downloads/mef_showroom1.zip

Thursday, October 29, 2009

Visual Studio 2010 and .NET 4.0 Features

I started working in Visual Studio since its early Visual Basic days. The latest in that series was 6.0.  Then came a series of .NET platform versions: Visual Studio .NET (Rainier, 2003-Feb),  Visual Studio .NET 2003 (Everett, 2003-Apr), Visual Studio 2005 (Whidbey, 2005-Oct) and Visual Studio 2008 (Orcas, 2007-Nov). The latest version of Microsoft Visual Studio is VS 2010 (Code Name: Hawaii) and is expected to be available for public in March, 2010. I tried out the recently released Beta 2 version of VS 2010 and its cool.

vs2010
Here are some of the new features (collected from various blogs including ScottGu's Blog and Kevin McNeish's Blog):
Visual Studio
  • Fresh look and feel with a blue based new logo and color theme.
  • Works side by side with VS 2008 and supports Multi Targeting (.NET 2.0, 3.0, ...).
  • New Product Lineup (Express, Professional, Premium, Ultimate).
  • Multi-Monitor Support (editors, designers and tool-windows).
  • Silverlight UI layout support.
  • Data binding support for both WPF and Silverlight.
  • Zoom in/out of any code editing window or text editing window.
  • Call hierarchy for C# is available at design time (Similar to stack trace; Right click on a symbol(method or class, etc.) and choose View Call Hierarchy).
  • Naviagate To (Edit > Navigate To or Ctrl+Comma) option to do quick search for a symbol or file in the source code (can search part of a name or abbreviation like IC for InitializeComponent, and can specify multiple strings separated by space).
  • Highlight References: Put the cursor on a symbol and after a short delay, all its references are highlighted. Or use Find all references (Right click on a symbol and choose Find All References) to see all its instances.(Ctrl-Shift-up/down arrow to cycle)
  • Consume First Development: Even if there is no class by name Person, you can type Person obj = new Person(); and then choose to generate the class. (Ctrl+ Dot)
  • Tools > Extension Manager to manage add-ins.
.NET Framework 4.0
  • Dynamic Language Support. [kind of late binding: dynamic Car = GetCar();]
  • MEF (Managed Extensibility Framework) for developing applications that supports plugins.
  • Optional Parameters [Supply a default value to make it optional: public void CreateBook(string title="No Title", string isbn = "0-00000-000-0"){}]
  • Named Parameters [Supply parameter values in any order specifying its name: CreateBook(isbn: "5-55555-5555-5"); or CreateBook("Book Title", isbn: "5-55555-5555-5");]
  • Co-variance and Contra-variance support [IEnumerable<string> strings = GetStrings();IEnumerable<object> objects = strings; is now possible.]
ASP.NET 4.0
  • Starter Project Templates (Installed & Online; Empty, Normal, MVC, Ajax, etc.).
  • Clean Web.Config Files.
  • Code Optimized Web Development Profile(Or Tools>Options>HTML Designer>Off Designer)
  • ASP.NET, HTML, JavaScript Snippet Support.
  • Auto start: Only on IIS 7.5 (well-defined approach to perform expensive application startup).
  • URL Routing with ASP.NET 4 Web Forms.
WPF 4.0
  • New controls: DataGrid, DatePicker, and Calendar
  • Bag O’ Tricks controls: AnimatingTilePanel, ColorPicker, InfoTextBox, ListPager, NumericUpDown, Reveal, TransitionsPresenter, TreeMapPanel.
  • Extra control: Windows 7 & Office Ribbon Control
  • Graphics improvements: Cached Composition, Pixel Shader 3 Support, LayoutRounding, Animation Easing Function, CleartypeHint
  • Text improvements: New Text Rendering Stack, Display-optimized character layout, explicitly selecting aliased, grayscale, or ClearType rendering modes, optimizing text hinting and snapping, support for fonts with embedded bitmaps, BindableRun (Run.Text), Custom Dictionaries, Selection and Caret Brush
  • Windows 7 Multitouch Support: Multi-touch Manipulation, Inertia (Pan, Zoom, Rotate) events on UIElement, Raw multi-touch events (Up, Move, Down) on UIElement, UIElement3D and ContentElement, Multiple capture supporting multiple active controls, ScrollViewer enhancement to support multi-touch panning, Touch device extensibility, Future Surface SDK compatibility
  • Windows 7 Shell Integration: Jump List (Tasks, Items, Recent and Frequent Lists) and Taskbar (Progress bar, Overlay Icon, Thumbnail buttons with commanding support, Description Text) integration
  • Fundamentals: New XAML/BAML Parser Engine, Data Binding Support for DLR, Visual State Manager (VSM), HTML-XBAP Script Interop, UIAutomation Virtualization, SynchronizedInput Pattern
  • Deployment: .NET Framework 4 Client Profile, Full Trust XBAP Deployment
Win Forms 4.0
  • No new features or controls!
  • Will maintain compatibility for applications already written in WinForms.
  • Bug fixes and perf improvements.

Friday, October 16, 2009

WiX - Windows Installer XML

Windows Installer

The Windows Installer is an engine for the installation, maintenance, and removal of software on modern Microsoft Windows systems. The installation information, and often the files themselves, are packaged in installation packages, commonly known as "MSI files", from their default file extension.
Windows Installer is positioned as an alternative to stand-alone executable installer frameworks such as NSIS, and older versions of InstallShield and Wise.
MSI packages can be created using Visual Studio through a Setup project or using third party tools like InstallShield, Wise Installer and WiX.

Windows Installer XML

The Windows Installer XML (WiX, pronounced "wicks"), is a free software toolset that builds Windows Installer (MSI) packages from an XML document. It supports both command-line environment and integrated Visual Studio environment.
The WiX distribution includes Votive, a Visual Studio add-in that allows creating and building WiX setup projects using the Visual Studio IDE. Votive supports syntax highlighting and IntelliSense for .WXS source files and adds a WiX setup project type to Visual Studio.

WiX Download

WiX can be downloaded from http://sourceforge.net/projects/wix/files/. The latest version is 3.0 and the downloaded zip file (wix3.0.5419.0-x86-setup.zip) will contain Wix3.msi. Double click on this after closing all the Visual Studio instances. This will install all the required Wix tools (there are a lot of them and they have interesting names all associated to the wicks of a candle) to %PROGRAMFILES%\ \Windows Installer XML v3\ and the required Visual Studio add-in and project templates.
The bin sub folder under this contains all the tools like candle.exe (compiler and that convert source code into object files), light.exe (linker that take multiple object files and resources to create final setup package), and other tools like dark, light, heat, smoke, torch, etc. The doc sub folder has a detailed help file by name Wix.chm. A detailed tutorial is available at http://wix.sourceforge.net/manual-wix3/main.htm.

Visual Studio WiX Project

First create a sample application to test the WiX. I created a simple Windows Application project. Now add a new WiX Project to the solution (Project Type: WiX, Template: WiX Project) and name it as SampleApp.Setup.
The project will have a default ‘Product.wxs’ file containing the WiX source code to create an MSI package. The WiX source code is nothing but a set of XML tags. Remove the commented tags in the default file and add application exe as shown below:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Id="b464316e-5c06-4cae-be36-0748d51ceb03"
           Name="SampleApp.Setup"
           Language="1033"
           Version="1.0.0.0"
           Manufacturer="SampleApp.Setup"
           UpgradeCode="e0ad76e3-7ad8-436f-b3cd-9f30fcabb1d9">
    <Package InstallerVersion="200"
             Compressed="yes" />

    <Media Id="1"
           Cabinet="media1.cab"
           EmbedCab="yes" />

    <Directory Id="TARGETDIR"
               Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="INSTALLLOCATION"
                   Name="SampleApp.Setup">
          <Component Id="ProductComponent"
                     Guid="9102229d-8f5c-474d-be69-00085b3230a2">
            <File Id="SampleApp.exe"
                  Name="SampleApp.exe"
                  Source="$(var.SolutionDir)\SampleApp\$(var.OutDir)SampleApp.exe"
                  KeyPath="yes"
                  Checksum="yes"/>
          </Component>
        </Directory>
      </Directory>
    </Directory>

    <Feature Id="ProductFeature"
             Title="SampleApp.Setup"
             Level="1">
      <ComponentRef Id="ProductComponent" />
    </Feature>
  </Product>
</Wix>
Let us now inspect each elements of this file:
WiX: Root element of a WiX installer.
Product: An msi will always contain a single product which is the software we are planning to install. It requires a unique GUID and we can specify other properties like product name, version and manufacturer.
Package: Used to set the packaging properties. Basically we say compression is needed or not.
Media: Describes the installation media for the installer. By default it is a cabinet file named media1.cab which is embedded within the msi file. All the other files will be compressed to this cab file.
Directory: Now we need to specify a group of directory structure that we plan to build on the target machine. All these directories should be within the virtual TARGETDIR directory. In this case, we have the root folder as ‘ProgramFilesFolder’ which is the keyword for system folder ‘%PROGRAMFILES%\’ which will be typically to ‘C:\Program Files\’. Inside this directory we are creating another directory named ‘SampleApp.Setup’. So our final destination folder will be ‘C:\Program Files\SampleApp.Setup\’.
Component: The component is the atomic unit of things to be installed. It consists of resources—files, registry keys, shortcuts or anything else—that should always be installed as a single unit.
File: This represents a file that we need to copy to the target system. Here we are specifying the output exe of our simple application. Note that ‘$(var.SolutionDir)’ is a preprocessor variable that will point to the actual solution directory. Same way, ‘$(var.OutDir)’ represents the project output directory (bin\Debug or bin\Release).
Feature: Features are separated parts of the application that we offer the user to decide whether to install or not. Examples are core files, samples, documentation, etc. Here we have just single feature which is our lone app exe referred by Component Id.
Building this project will create an msi named SampleApp.Setup.msi at the bin\Debug folder of the setup project.
This is the very basic installer without any user interaction options, and it will just show a progress bar of the installation. After completion, you can see that SampleApp .exe is copied to C:\Program Files\SampleApp.Setup\ folder. There are no start menu items or shortcuts created, but there will be an entry in Add or Remove programs list (Programs and Features) from where you can uninstall this program.

WiX User Interface

Adding a standard user interface to the installer is very easy with WiX. First add a reference to WixUIExtension.dll (available in’ %PROGRAMFILES%\ Windows Installer XML v3\bin\’ folder) in the setup project. Now add the following line just above the Product closing tag.
<UIRef Id="WixUI_Minimal"/>
UIRef tells WiX which UI style should be used and we have chosen the ‘Minimal’ with basic options. That’s it. Now build the project and run the installer. It will have a default user interface with license page, progress page and a finish page.
If you re-run the installer after installing it once, the UI will change to provide a ‘Repair’ or ‘Remove’ option. ‘Remove’ can be used to uninstall the program.
Providing the user with an option to choose the installation directory is also very easy. Instead of the UIRef element used above, add the following two lines:
<Property Id="WIXUI_INSTALLDIR"
              Value="INSTALLLOCATION" />
<UIRef Id="WixUI_InstallDir"/>
Here we have chosen the ‘InstallDir’ UI style and the selected directory is assigned to the ‘INSTALLLOCATION’ value which we are referring within the directory structure. Now when you run this new installer, the user will have an option to choose the installation directory.
Other UIRef include WixUI_FeatureTree (allows features to be selected) and WixUI_Mondo (provides typical, custom and complete install options).

WiX User Interface Customization

You can customize some visual aspects of the user interface by simply providing replacement files. To add your own license file for example, add a license rtf file to the setup project and then add the below line just above Produc> closing tag:
<WixVariable Id="WixUILicenseRtf" Value="license.rtf" />
Other such options are:
<WixVariable Id="WixUIBannerBmp" Value="mybanner.bmp" />
<WixVariable Id="WixUIDialogBmp" Value="mydialog.bmp" />
Dialog is the first install page’s background image (493 x 312 pixels bmp) and Banner is the top banner image on subsequent pages (493 x 58 pixels bmp).
Download a complete Visual Studio 2008 Solution with sample WiX project from here: wixsample.zip. And here is the complete WiX code for that:
<?xml version="1.0" encoding="UTF-8"?>
<!--Author: Sameer C Thiruthikad | Last Modified: 2009-Oct-16-->
<!--Defining some constants-->
<?define Property_ProductName = "My Sample App" ?>
<?define Property_Manufacturer = "My Company" ?>

<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
  <Product Name='$(var.Property_ProductName)'
           Id='{C24FBDCE-AD5D-4f0d-AD4B-9E75EB78D231}'
           UpgradeCode='{DCE43671-9C09-4fb0-AC05-34D4AF71563E}'
           Language='1033'
           Codepage='1252'
           Version='1.0.0'
           Manufacturer='$(var.Property_Manufacturer)'>

    <!--These properties will appear in Windows Explorer-->
    <Package Id='*'
             Keywords='Installer'
             Description="$(var.Property_ProductName) Installer"
             Comments='$(var.Property_Manufacturer) $(var.Property_ProductName)'
             Manufacturer='$(var.Property_Manufacturer)'
             InstallerVersion='100'
             Languages='1033'
             Compressed='yes'
             SummaryCodepage='1252' />
    
    <Media Id="1"
           Cabinet="media1.cab"
           EmbedCab="yes" />

    <!--Defining target directory structure-->
    <Directory Id='TARGETDIR'
               Name='SourceDir'>
      <!--Primary install folder: %PROGRAMFILES%\My Company\My Sample App\ ; Sub folders: Resources-->
      <Directory Id='ProgramFilesFolder'
                 Name='PFiles'>
        <Directory Id='ManufacturerFolder'
                   Name='$(var.Property_Manufacturer)'>
          <!--Application files to the primary install fodler-->
          <Directory Id='INSTALLDIR'
                     Name='$(var.Property_ProductName)'>

            <Component Id='MyCompany.MyApp'
                       Guid='{36EF4819-D4C6-4bc6-AA7D-4D41DC2E2342}'>
              <File Id='SampleApp.exe'
                    Name='SampleApp.exe'
                    DiskId='1'
                    Source='$(var.SolutionDir)\SampleApp\$(var.OutDir)SampleApp.exe'
                    KeyPath='yes'>
                <Shortcut Id="ProgramMenu.Shortcut.App"
                          Directory="ProgramMenuSubFolder"
                          Name="$(var.Property_ProductName)"
                          WorkingDirectory='INSTALLDIR'
                          Icon="AppIcon.ico"
                          IconIndex="0"
                          Advertise="yes" />
                <Shortcut Id="Desktop.Shortcut.App"
                          Directory="DesktopFolder"
                          Name="$(var.Property_ProductName)"
                          WorkingDirectory='INSTALLDIR'
                          Icon="AppIcon.ico"
                          IconIndex="0"
                          Advertise="yes" />
              </File>
            </Component>

            <Component Id='MyCompany.MyApp.Helpers'
                       Guid='{C60F6F97-CBC1-4ee7-89D8-3D4E5F72DD00}'>
              <File Id='HelperDLL'
                    Name='Helper.dll'
                    DiskId='1'
                    Source='$(var.SolutionDir)\SampleApp\$(var.OutDir)Helper.dll'
                    KeyPath='yes' />
            </Component>

            <Component Id='MyCompany.MyApp.Manual'
                       Guid='{DB40393C-2D35-4007-A0EF-E0846F1A70E4}'>
              <File Id='Manual'
                    Name='Manual.pdf'
                    DiskId='1'
                    Source='$(var.SolutionDir)\SampleApp\$(var.OutDir)Manual.pdf'
                    KeyPath='yes'>
                <Shortcut Id="ProgramMenu.Shortcut.Manual"
                          Directory="ProgramMenuSubFolder"
                          Name="Instruction Manual"
                          Advertise="yes" />
              </File>
            </Component>

            <!--Resources to the Resources sub folder-->
            <Directory Id="AppResources"
                       Name="Resources" >
              <Component Id="MyCompany.MyApp.Resources"
                         Guid="{F25B9D53-9924-4a6c-B0F7-C5188943F474}">
                <File Id="image.jpg"
                      Name="image.jpg"
                      Source="$(var.SolutionDir)\SampleApp\$(var.OutDir)Resources\image.jpg"
                      Checksum="yes"/>
              </Component>
            </Directory>
          </Directory>
        </Directory>
      </Directory>

      <!--Define Start menu folder-->
      <Directory Id="ProgramMenuFolder"
                 Name="Programs">
          <Directory Id="ProgramMenuSubFolder"
                     Name="$(var.Property_Manufacturer) $(var.Property_ProductName)">
            <Component Id="MyCompany.MyApp.Shortcut"
                       Guid="{3C08CF93-5203-49fe-B545-005C225DA334}">
              <!--Any extra folder we creare under user profile need to be marked for deletion-->
              <RemoveFolder Id='ProgramMenuSubFolder'
                            On='uninstall' />
              <!--This is also required?!-->
              <RegistryValue Root='HKCU'
                             Key='Software\[Manufacturer]\[ProductName]'
                             Type='string'
                             Value=''
                             KeyPath='yes' />
            </Component>
          </Directory>
      </Directory>

      <!--Define Desktop folder-->
      <Directory Id="DesktopFolder"
                 Name="Desktop" />
    </Directory>

    <!--Register all components under a single feature-->
    <Feature Id='Complete'
             Level='1'>
      <ComponentRef Id='MyCompany.MyApp' />
      <ComponentRef Id='MyCompany.MyApp.Helpers' />
      <ComponentRef Id='MyCompany.MyApp.Manual' />
      <ComponentRef Id='MyCompany.MyApp.Shortcut' />
      <ComponentRef Id='MyCompany.MyApp.Resources' />
    </Feature>
    
    <!-- The icon that appears in Add & Remove Programs. -->
    <Property Id="ARPPRODUCTICON"
              Value="appicon.ico" />

    <!--UI style is set to InstallDir (User will have directory selection)-->
    <UIRef Id="WixUI_InstallDir"/>
    <Property Id="WIXUI_INSTALLDIR"
              Value="INSTALLDIR" />

    <!--Sepcify license file-->
    <WixVariable Id="WixUILicenseRtf"
                 Value="license.rtf" />

    <!--Specify initial page's background image-->
    <WixVariable Id="WixUIDialogBmp"
                 Value="welcome.bmp" />

    <!--Specify subsequent page's banner image-->
    <WixVariable Id="WixUIBannerBmp"
                 Value="banner.bmp" />

    <!--Define the icon used for shortcuts and installer-->
    <Icon Id="AppIcon.ico"
          SourceFile="appicon.ico" />
  </Product>
</Wix>
                            

Tuesday, September 01, 2009

Desklighter Update: Beta 2 with more customization options

The latest version of the Desklighter tool is now available for free download from IdentityMine Blendables Labs: http://blendables.com/labs/Desklighter/Default.aspx

 

desklighterbutton_white

“Desklighter is a windows utility that creates standalone windows applications from Silverlight xap files. Desklighter helps you in sharing your Silverlight applications as independent executables without having to worry about the hosting infrastructure. Unlike Silverlight Out-of-Browser(OOB) applications that run only on the installed computer, executables created by Desklighter are truly portable.”

See some sample games and demos created using Desklighter at http://sites.google.com/site/silverlightoffline

This new version of Desklighter has a settings panel providing more options to customize the executable application window. The settings available are Height and Width to control default application window size, border type (Re-sizable, fixed, none), application icon, background color, and window title. If the Silverlight application is expecting initial parameters, that can be supplied as well. It also supports transparency and it is possible to create custom shaped Silverlight standalone applications by setting the Background as 'Transparent' and choosing the 'No Border' option.

The recently released Silverlight 3.0 Out-of-Browser (OOB) feature opens up a lot of new scenarios as explained by Ashish Shetty. It surely is a great feature and will evolve to provide more options with upcoming releases of Silverlight. But it doesn’t help you in making your application portable. OOB helps in storing a hosted Silverlight application onto your desktop for running it from outside the browser. These applications will run only from the systems where they were installed.

However, applications created using Desklighter can be copied to another computer and it will work from it without any issues. If the computer doesn’t have Silverlight installed, the application will show a banner (default ‘No Silverlight’ experience) prompting the user to download and install the Silverlight plug-in.

Note that Desklighter is best suited for making already existing self contained Silverlight applications (where all the dependent resources are available within the xap file) portable. Examples include games, demos, proof-of-concepts, presentations, electronic brochures, tools and utilities.

Tuesday, August 18, 2009

Silverlight 3 Offline / OOB/ Out Of Browser Feature

Introduction

It is possible to configure Silverlight-based applications so that users can install them from their host Web pages and run them outside the browser. This feature is known by the name ‘OOB’ or ‘Out-of-Browser’ support, and sometimes just ‘Offline’ support.

Try a sample online or download the source code.

Configuration

  • Go to the Project Properties window (Right click on the Silverlight project in Visual Studio 2008 and choose ‘Properties’).
  • On the ‘Silverlight’ tab, select ‘Enable running application out of the browser’.
  • Click on the ‘Out-of-Browser Settings…’ button.
  • Fill or change the details like Window Title (Appears in the title bar of the out-of-browser application window), Width and Height (Indicates the dimensions of the out-of-browser application window; default is 800x600), Shortcut name (Appears in the out-of-browser installation dialog box and on the installed application shortcut or shortcuts), and Download description (Appears as a tooltip on the installed application shortcuts). Also assign application icon in a set of standard sizes (The operating system chooses the most appropriate icon to display in the installation dialog box, the application window, Windows Explorer, and Windows taskbar/Macintosh dock bar). These icons must be ‘png’ files and need to be added to the project initially with ‘Build Action’ set as ‘Content’. Optionally, 'Enable GPU Acceleration' can be turned on for graphics rich applications to enhance graphics performance by using hardware acceleration.


The values in the ‘Out-of-Browser Settings’ dialog box is used to generate an ‘OutOfBrowserSettings.xml’ file located in the project Properties folder. Any changes to this file are reflected in the designer. This file is used to populate the application manifest (AppManifest.xaml) with the specified values.
<OutOfBrowserSettings ShortName="MySloob Application" 
                      EnableGPUAcceleration="False" 
                      ShowInstallMenuItem="True">
  <OutOfBrowserSettings.Blurb>MySloob Application on your desktop; at home, at work or on the go.</OutOfBrowserSettings.Blurb>
  <OutOfBrowserSettings.WindowSettings>
    <WindowSettings Title="MySloob Application" Height="400" Width="600" />
  </OutOfBrowserSettings.WindowSettings>
  <OutOfBrowserSettings.Icons>
    <Icon Size="16,16">Icons/MySloob16.png</Icon>
    <Icon Size="32,32">Icons/MySloob32.png</Icon>
    <Icon Size="48,48">Icons/MySloob48.png</Icon>
    <Icon Size="128,128">Icons/MySloob128.png</Icon>
  </OutOfBrowserSettings.Icons>
</OutOfBrowserSettings>
Installation
When an application is properly configured for OOB, a new right-click menu option will be available as ‘Install <ApplicationName> Application onto this computer…’. Clicking on this will launch the installer dialog where the user can choose to create shortcuts on Start menu and Desktop. When ‘OK’ is clicked, the application will be installed to the local computer and it will be launched in a new application window. ‘Remove this application…’ right-click menu will now be available within this application to uninstall it from the computer.




Internals
If you look at the installed application’s shortcut properties, you will see that the target points to ‘C:\Program Files\Microsoft Silverlight\sllauncher.exe 1527765212.localhost’.

If you search for that random number (in my case: 1527765212) in Windows explorer, you will find a folder like this:

C:\Users\<user.name>\AppData\LocalLow\Microsoft\Silverlight\OutOfBrowser\1527765212.localhost

sllauncher.exe is the ‘Microsoft Silverlight Out-of-Browser Launcher’ application that gets installed along with Silverlight. It is a win32 application that loads the Silverlight application in its own browser host.

When you install a Silverlight OOB application, the XAP file is downloaded to the local computer and is stored in a folder within the user’s local app data called as ‘offline application cache’. The folder is named with a unique AppId which consists of a random number and the source of origin of the application (in this case: localhost). This folder will also have the application meta data and an index.html which has an object tag to load the Silverlight application.

sllauncher.exe takes this AppId (Examples: 1527765212.localhost, 1930341777.wayfarer.bizhat.com) as a parameter and then sets its window according to the metadata available in the specified offline application cache. It then loads the index.html in its browser host which in turn will display the Silverlight application.
metadata:
ShortcutName=MySloob Application
Name=MySloob Application
Title=MySloob Application
Description=MySloob Application on your desktop; at home, at work or on the go.
AppID=1527765212.localhost
RuntimeVersion=3.0.40624.0
FinalAppUri=file:///C:/Temp/MySloob/MySloob/Bin/Debug/MySloob.xap
OriginalSourceUri=file:///C:/Temp/MySloob/MySloob/Bin/Debug/MySloob.xap
SourceDomain=localhost
WindowHeight=400
WindowWidth=600
EnableGPUAcceleration=False
TrimmedName=MySloob Application
TrimmedTitle=MySloob Application
TrimmedSourceDomain=localhost
CustomIcon=1
LaunchPath=C:\Users\sameer.thiruthikad\AppData\LocalLow\Microsoft\Silverlight\OutOfBrowser\1527765212.localhost\index.html

index.html:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">


<html xmlns="http://www.w3.org/1999/xhtml" >
  <!-- saved from url=(0014)about:internet -->
<head>
  <style type='text/css'>
    html, body { height: 100%; overflow: auto; }
    body { padding: 0; margin: 0; }
    #silverlightControlHost { height: 100%; }
  </style>
</head>
<body scroll="no" onload="document.getElementById('_sl').focus()">
    <div id="silverlightControlHost">
      <object id='_sl' data="data:application/x-silverlight," type="application/x-silverlight" width="100%" height="100%">
          <param name="source" value="offline://1527765212.localhost"/>
          <param name="background" value="White"/>
          <param name="enableGPUAcceleration" value="False"/>
          <a href="http://go.microsoft.com/fwlink/?LinkID=124807" style="text-decoration: none;">
              <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>
          </a>
      </object>
      <iframe style='visibility:hidden;height:0;width:0;border:0px'></iframe>
    </div>
</body>
</html>

Sample Application

There are a set of classes and methods available in Silverlight to install an application through code, to check for updates, to determine network status, etc. These are illustrated through the sample below:

XAML:
<Grid x:Name="LayoutRoot"
          Background="Beige">
        <StackPanel  HorizontalAlignment="Center">
            <TextBlock Text="Welcome to 'MySloob' - A sample Silverlight Out-Of-Browser Application!"
                       HorizontalAlignment="Center" />
            <TextBlock x:Name="uxDescription"
                       Text="()"
                       HorizontalAlignment="Center" />
            <Button x:Name="uxInstall"
                    Margin="20"
                    Height="50"
                    Width="200"
                    Content="Install Me"
                    Click="uxInstall_Click" />
            <Ellipse Height="100"
                     Width="{Binding ElementName=uxSlider,Path=Value}">
                <Ellipse.Fill>
                    <LinearGradientBrush EndPoint="0.5,1"
                                         StartPoint="0.5,0">
                        <GradientStop Color="Orange"
                                      Offset="0" />
                        <GradientStop Color="Red"
                                      Offset=".5" />
                        <GradientStop Color="Yellow"
                                      Offset="1" />
                    </LinearGradientBrush>
                </Ellipse.Fill>
            </Ellipse>
            <Slider x:Name="uxSlider"
                    Margin="25"
                    Width="300"
                    Value="200"
                    Minimum="100"
                    Maximum="300" />
            <Button x:Name="uxCheckUpdate"
                    Height="50"
                    Width="200"
                    Content="Check Update"
                    Click="uxCheckUpdate_Click" />
            <TextBlock x:Name="uxOOBStatus"
                       Margin="0,25,0,0"
                       Foreground="Blue"
                       Text="OOB Status"
                       HorizontalAlignment="Center" />
            <TextBlock x:Name="uxInstallStatus"
                       Foreground="Brown"
                       Text="Install Status"
                       HorizontalAlignment="Center" />
            <TextBlock x:Name="uxNetworkStatus"
                       Foreground="Black"
                       Text="Network Status"
                       HorizontalAlignment="Center" />
            <TextBlock Text="Last Modified: 2009-August-18, 05:00 PM IST by Sameer C Thiruthikad"
                       HorizontalAlignment="Center" />
        </StackPanel>
    </Grid>
C# Code:
public MainPage()
{
    InitializeComponent();

    UpdateUI();
    Application.Current.InstallStateChanged += new EventHandler(app_InstallStateChanged);
    Application.Current.CheckAndDownloadUpdateCompleted += new CheckAndDownloadUpdateCompletedEventHandler(app_CheckAndDownloadUpdateCompleted);
    System.Net.NetworkInformation.NetworkChange.NetworkAddressChanged += new System.Net.NetworkInformation.NetworkAddressChangedEventHandler(NetworkChange_NetworkAddressChanged);
}

private void uxInstall_Click(object sender, RoutedEventArgs e)
{
    try
    {
        Application.Current.Install();
    }
    catch (InvalidOperationException)
    {
        MessageBox.Show("The application is already installed.");
    }
}

void app_InstallStateChanged(object sender, EventArgs e)
{
    UpdateUI();
}


private void uxCheckUpdate_Click(object sender, RoutedEventArgs e)
{
    Application.Current.CheckAndDownloadUpdateAsync();
}

void app_CheckAndDownloadUpdateCompleted(object sender, CheckAndDownloadUpdateCompletedEventArgs e)
{
    if (e.UpdateAvailable)
    {
        MessageBox.Show("An application update has been downloaded. Please restart.");
    }
    else
    {
        MessageBox.Show("There is no update available.");
    }
}

void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)
{
    UpdateUI();
}

private void UpdateUI()
{
    if (Application.Current.InstallState == InstallState.Installed)
    {
        this.uxInstall.IsEnabled = false;
    }
    else
    {
        this.uxInstall.IsEnabled = true;
    }

    this.uxOOBStatus.Text = "OOB Status: " + Application.Current.IsRunningOutOfBrowser.ToString();
    this.uxInstallStatus.Text = "Install Status: " + Application.Current.InstallState.ToString();
    this.uxDescription.Text = "(" + Deployment.Current.OutOfBrowserSettings.Blurb + ")";
   
    bool online = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();

    if (online)
    {
        this.uxNetworkStatus.Foreground = new SolidColorBrush(Colors.Green);
        this.uxNetworkStatus.Text = "Network Status: Online";
    }
    else
    {
        this.uxNetworkStatus.Foreground = new SolidColorBrush(Colors.Red);
        this.uxNetworkStatus.Text = "Network Status: Offline";
    }
}
Try this sample online or download the source code.

Tuesday, August 11, 2009

My Windows 7 Experience

I installed Winodws 7 on my work computer yesterday. It is the latest Operating System from Microsoft after Vista. I was using Vista since long and had felt it was much better than XP. The initial release had many issues but the service pack that followed (SP1) fixed most of them. But still there were many areas for improvement in Vista, especially on the performance side.

win7

Windows 7 has successfully addressed many such pain areas in Vista and it performs better. Apart from the multi-touch support, there aren't many new visible features, as the Win 7 team has focused more on performance and compatibility issues.

It installed quickly and booted fast. The Enterprise edition (there are many editions to choose from) took only around 9 GB of my hard disk space after installation. The changing desktop background images are nice. The changes in taskbar look and behavior will not be missed. ‘Show desktop’ is now at the right most corner and has a new ‘peek’ feature. The quick launch bar is missing and taskbar takes up that role as well. Here you will have to do ‘Pin to Taskbar’ on applications in start menu to make them stick to task bar as quick launch icons. Then you wonder how to launch another instance of an application as the quick launch icon turns to a minimized application during launch. Well, learn a new short cut (Shift + Click) to do this. There are many such new features that is supposed to make our lives better. :)

I installed all my work applications and favorite tools and configured them to my liking. All of them worked without any issues. The touch feature in Windows 7 require a supporting hardware. We have one big HP Touch Smart system here where the touch features work nicely.

Monday, August 03, 2009

Microsoft Tag

A High Capacity Color Barcode (HCCB), also branded Microsoft Tag, is a type of barcode that uses shapes, instead of black-and-white lines or squares used by other barcode systems. HCCB is not intended to replace traditional barcodes, but rather enhance them by allowing more information to be stored.

Custom Tag

Creating Tags
  • Go to http://tag.microsoft.com
  • Associate your Live id (hotmail email address is fine) with the Tag site and sign in.
  • Click on the 'Create Tag' button and follow the directions.
  • Tag can be of type Url, Contact card, or plain text.
  • Once tag is created, the information we provided is stored in Microsoft servers and a unique id is associated with it. This id is encoded in a graphical image to generate the tag.
  • Click on the 'Render' button to get the generated tag in the format of your choice (png, pdf, jpg, etc).
  • It is also possible to get it in custom format so that it can be used by overlaying on another image.
Using Tags
  • The tags can be used anywhere in web (sites, blogs, etc.) as images.
  • Tags can be printed and used on real world objects like books, product package, etc.
  • They can even be printed big for displaying on a hoarding.
Reading Tags
  • Tags are read using a mobile device having camera.
  • The device need to have a software named 'Microsoft Tag Application' or simply 'Tag Reader' which can be installed freely from http://gettag.mobi.
  • Start this application in your device and just point the camera onto to a tag to read it.
  • It works by decoding the id encoded in the image and then connecting to internet to get the associated details from Microsoft servers.

To see more samples, visit my workshop page on this at: wayfarer.bizhat.com/techbites/workshop/tag.html

Monday, June 01, 2009

Microsoft Bing Decision Engine

Here comes a new search decision engine from Microsoft to replace it’s existing Live Search:
Here is a pretty looking view of it:
bing

Read more about it at: http://www.microsoft.com/presspass/presskits/bing/default.mspx

Monday, May 18, 2009

Wolfram Alpha Computational Knowledge Engine

Wolfram Alpha Answer Engine gets us to what people thought computers would be able to do 50 years ago: quickly find answers to all the factual questions!

Stephen Wolfram, the British physicist behind this recently launched project clarifies that Wolfram Alpha is a website with one simple input field that gives access to a huge system, with trillions of pieces of curated data and millions of lines of algorithms.

wolframalpha

It is not a search engine that lists out numerous links to information that exist on the web. Instead, it actually computes the answer using the available data and displays it in a easily readable format.

Link: http://www.wolframalpha.com/

Thursday, May 14, 2009

Microsoft Surface Applications - Deployment and Object Routing

Continued from: Microsoft Surface Tagged Objects and Tag Visualizations

When users interact with a Microsoft Surface unit, they launch the applications from Launcher.  Launcher is the menu that displays the applications that are available to users in a horizontal interactive strip.

surfacelauncher
 As part of deploying the Surface application, we must register it with Surface so that it is available in the Launcher. This is done by copying the application’s xml file to the Surface’s program data folder (%PROGRAMDATA%\Microsoft\Surface\Programs).

This application xml file is created by default when the Visual Studio project template is used. Otherwise, we can create a normal xml file with the file name equivalent as the project (executable) name and with the following tags.
<?xml version="1.0" encoding="utf-8" ?>
<ss:ApplicationInfo
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xmlns:ss="http://schemas.microsoft.com/Surface/2007/ApplicationMetadata">
  <Application>
    <Title>My Surface App</Title>
    <Description>This is a sample Surface application.</Description>
    <ExecutableFile>%ProgramFiles%\MyCompany\MyApp\MyApp.exe</ExecutableFile>
    <Arguments></Arguments>
    <IconImageFile>%ProgramFiles%\MyCompany\MyApp\Resources\icon.png</IconImageFile>
    <Preview>
      <PreviewImageFile>%ProgramFiles%\MyCompany\MyApp\Resources\iconPreview.png</PreviewImageFile>
    </Preview>
    <Tags>
      <ByteTag Value="C0">
        <Actions>
          <Launch />
        </Actions>
      </ByteTag>
    </Tags>
  </Application>
</ss:ApplicationInfo>
The <Application> tag specifies that this is a normal Surface application. Other options are <AttractApplication> for attract mode (similar to screen saver) applications and <ServiceApplication> for apps that run in the background and does not have a UI.

The <Title> is displayed on the Launcher all the time, and <Description> is displayed when the application is selected from the Launcher. <ExecutableFile> specifies the path to the actual application exe. If the application is accepting any command line arguments it can be supplied through <Arguments> tag. <IconImageFile> specifies the png image to be displayed in the Launcher as application icon and <Preview> specifies the image to be displayed when the application is selected in the Launcher. This can be a bigger static image(<PreviewImageFile>) or a slideshow of images(<SlideshowImageFile>) or a movie (<MovieFile>).

The <Tags> specify the tags used by the application and <Launch> is used to specify that the particular tag value is used for object routing (which is discussed later).

To summarize the deployment steps again:
  • Build your Surface application in Release mode.
  • Copy all the files from the build folder to any location in the Surface computer (typically %ProgramFiles%\CompanyName\ApplicationName\).
  • Make sure that this path is specified in the Application’s xml file.
  • Copy the Application’s xml file to (%PROGRAMDATA%\Microsoft\Surface\Programs folder.
That’s all to it and the application will now be available in the Launcher for the user to see and launch.

Tagged Object Routing
On 2009-May-10, Microsoft released its first Service Pack (SP1) to Surface 1.0 with lots of new features and improvements. Read about them at official Surface blog.

Object Routing is one of the new SP1 features that enable the developer to configure tagged objects which can open applications without using Launcher. The tagged object can be placed anywhere on the Surface interface (attract applications, other non-registered applications or the Launcher) to bring up the list of applications that are registered with that tag. The applications will appear as tiny bubbly icons that smoothly pops up from the object and can be launched by touching them.

surfaceobjectrouting 
To enable the object routing for an applications:
  • Specify the required type of tag (Byte/Identity) within the <Tags> section of the application’s xml file and specify its value and have the <Actions> as <Launch>.
<ByteTag Value="C0">
  <Actions>
    <Launch />
  </Actions>
</ByteTag>
or

<IdentityTag Series="4245A8E4901C2C0B">
  <Actions>
    <Launch /> 
  </Actions>
</IdentityTag>

I have used an example value of C0 for Byte tag and 4245A8E4901C2C0B for Identity tag.
  • Create a new registry key using this tag value under TagInfo section as below:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Surface\TagInfo\v1.0\ByteTags\C0
or

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Surface\TagInfo\v1.0\IdentityTags\4245A8E4901C2C0B
  • Add the following String Value items on this key
    • Text : ‘object routing card title’.
    • BoundingBoxWidth : ‘3.25’.
    • BoundingBoxHeight : ‘2.125’.
    • PhysicalCenterOffsetFromTagX : ‘0’.
    • PhysicalCenterOffsetFromTagY : ‘0’.
    • OrientationOffsetFromTag : ‘0’.
This specifies the size of tagged object (business card size is 3.25 x 2.125 inches) and the location of the tag within this object (Zero means there is no offset from the center of the object; the tag is exactly on the center of this business card sized object)

Note that the other registry settings (enabled by default) to enable Object Routing (HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Surface\v1.0\Shell\EnableObjectRouting ) must be set as well.

That’s all the settings we need to do to get object routing work. Now if you place a tag with the specified value, all the applications that have this tag value in their xml file registered will popup from this object.

If you have done everything right, and still its not working as expected, refer the event log (run the command eventvwr) and navigate to Applications and Services Logs/Microsoft/Surface/Shell/Operational for any possible warnings or errors. Chances are that there is some error in the application's xml file or the registry settings. A sample warning (when the required registry entry is not present) looks like below:
The application info file C:\ProgramData\Microsoft\Surface\Programs\Macroni.xml refers to tag 29EB049F73061803, however, some configuration information for 29EB049F73061803 is missing from the registry. The default value '2.125' will be used for the missing setting.
Path to the tag's missing configuration setting in the registry:
HKEY_LOCAL_MACHINE\Software\Microsoft\Surface\TagInfo\v1.0\IdentityTags\29EB049F73061803\BoundingBoxHeight
Happy coding!

Monday, May 11, 2009

Microsoft Surface Tagged Objects and Tag Visualizations

Continued from Developing Microsoft Surface Applications

Microsoft Surface applications can recognize special tags besides fingers and  objects. These tags are similar to bar codes in concept and can store a particular value which can be retrieved by Surface’s vision system.

Tags are a pattern of white dots (infrared reflective) in black background (infrared absorbing) and are normally printed on a card or are printed and stuck to the plain surface of an object. Such objects with a tag are called as Tagged Objects.

Microsoft Surface supports two types of tags:

surfacetags
Byte Tags
  • Stores 8 bits of data (1 byte).
  • 256 possible unique values.
  • Smaller size (3/4 x 3/4 inches).
  • Reliable tracking even for faster moving tags.
  • Represented in code by ByteTag structure.
  • ByteTag.Value property represents the tag value.
Identity Tags
  • Stores 128 bits of data (two 64 bit values).
  • Larger range of possible unique values (i.e. 340,282,366,920,938,000,000,000,000,000,000,000,000).
  • Larger size (1 x 1 inches).
  • Functions better when tags are stationary or nearly stationary.
  • Represented in code by IdentityTag structure.
  • IdentityTag.Series and IdentityTag.Value together represents the tag value.
These tags are usually pre-printed and available from Microsoft or are printed using special tools that come with the Surface SDK.

Now let us build a sample application that deals with tagged objects. Create a new Surface project and add three Tag Visualization items (Add > New Item > Visual C# > Surface > v1.0 > Tag Visualization (WPF)). These items defines the UI that appears when a tagged object is placed on Surface. For now, let us just specify a height and width for it and then have a blank grid with a background color.
<s:TagVisualization x:Class="TagSample.BlueTags"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:s="http://schemas.microsoft.com/surface/2008"
    Loaded="BlueTags_Loaded" Height="50" Width="50">
    <Grid Background="Blue">
            
    </Grid>
</s:TagVisualization>

Now add the following XAML code in the SurfaceWindow1.xaml


<Grid Background="{StaticResource WindowBackground}" >
  <s:TagVisualizer VisualizationAdded="OnVisualizationAdded" >
    <s:TagVisualizer.Definitions>
      <!-- ByteTag: 10 = A -->
      <s:ByteTagVisualizationDefinition Value="10"
                                        Source="BlueTags.xaml">
      </s:ByteTagVisualizationDefinition>
      
      <!-- ByteTag: 250 = FA -->
      <s:ByteTagVisualizationDefinition Value="250"
                                        Source="RedTags.xaml">
      </s:ByteTagVisualizationDefinition>

      <!-- IdentityTag: 500 = 1F4, 1000 = 3E8 -->
      <s:IdentityTagVisualizationDefinition Series="500" Value="1000"
                                        Source="YellowTags.xaml">
      </s:IdentityTagVisualizationDefinition>
      
    </s:TagVisualizer.Definitions>
    <DockPanel LastChildFill="False">
      <TextBlock x:Name="uxDisplay"
                 HorizontalAlignment="Center"
                 DockPanel.Dock="Bottom"
                 Text="Watch here"/>
    </DockPanel>
  </s:TagVisualizer>
</Grid>

TagVisualizer is a content control that automatically displays visualization objects when a tag is placed on the control.  We keep this as the root containing control within Grid. Then we define three tags using TagVisualizationDefinition. Each definition specifies what kind of tag (Byte or Identity) we are using, its value, and the source file for TagVisualization. Finally we have a TextBlock to display the values.

Also note that we have defined VisualizationAdded event on the TagVisualizer. This gets fired whenever a tag is placed. Add the following code to handle this event.


void OnVisualizationAdded(object sender, TagVisualizerEventArgs e)
{
    String type = "";
    String value = "";

    if (e.TagVisualization.VisualizedTag.Type == TagType.Byte)
    {
        type = "Byte Tag";
        value = e.TagVisualization.VisualizedTag.Byte.Value.ToString();
    }
    else if (e.TagVisualization.VisualizedTag.Type == TagType.Identity)
    {
        type = "Identity Tag";
        value = e.TagVisualization.VisualizedTag.Identity.Series.ToString() + " - " + e.TagVisualization.VisualizedTag.Identity.Value.ToString();
    }

    uxDisplay.Text = type + ":" + value;
}

In this code, we are retrieving the tag information from the event arguments and then display it in a text box.

surfacetagsample

Run the application and try placing different tags. Note that the integer values need to be converted to Hexadecimal format while using in the simulator (I use Windows Calculator, change its View to Scientific, use ‘Dec’ option for decimal, type in a number and then choose ‘Hex’ option to convert it to Hexadecimal value) (E.g.: Value 10 in Hex = A).

Continued to: Microsoft Surface Applications - Deployment and Object Routing