UserControls in Silverlight for Windows Embedded (Part-1)

Hello, I am Ajay Suri a developer in Silverlight for Windows Embedded (SWE) team at Microsoft. In this series of articles, I am going to cover the workings of UserControls in SWE.

This post is Part-1 of the series and in this I will cover the following.

1) Creating a simple UserControl in Blend and using WEST to generate SWE application.

2) Understand the WEST generated code

Creating a simple UserControl and using WEST to generate SWE application

UserControls in Silverlight for Windows Embedded (SWE) are similar to the UserControls in the desktop Silverlight. They are the basic re-usable pieces of xaml. In the SWE development model, first the Silverlight C# application containing the UserControl is created in Expression Blend. Then SWE application is created using WEST.

Step 1 - Create a new SWE application C# project in Expression Blend

In a previous post, Paul Monson explained how to create a SWE application using Expression Blend and then importing into Visual Studio. Using those steps, I created a simple SWE application using Expression Blend. Let us name the project UserControlSampleCSharp.

The project will look like the following in Blend Project tab.

clip_image001

Blend creates several files, let us not get into details of each file, but for now let us concentrate on the MainPage.xaml which is the first XAML that will be shown when the application starts.

Step 2 – Add a new UserControl to the Project.

From the global menu choose Project –> “Add New Item..” which brings up the following screen. UserControl is chosen by default. Leave it as it is, and give the UserControl a name. Let us call it “MyFirstUserControl” and click OK. This will create “MyFirstUserControl.xaml” and “MyFirstUserControl.Xaml.cs” files.

clip_image002

Now change the background color of the UserControl by open “MyFirstUserControl.xaml” in XAML view and adding modify the XAML to make the Grid Background color Green.

<Grid x:Name="LayoutRoot" Background="Green"/>

Step 3: Add the UserControl to MainPage

Now, Build the project (Project –> Build Project) . One it builds sucessfully, navigate to “MainPage.xaml”. Click on Assets arrow, and then click on Projects to bring up the controls from the project. Select the “MyFirstUserControl”.

clip_image004

In the design view of “MainPage.xaml”, drop the UserControl. You can do it multiple times, based on what your application may need, but for now, let us do it twice just for the demo purpose.

clip_image006

That’s it. You have created a UserControl and re-used it twice in another page. This is a very simple demo just to show how to re-use. Build and run the project, you should see the application inside the browser window with two green rectangles.

Step 3: Use WEST to generate the SWE application from the C# project

You can do this by following the steps outlined in the previous post about creating your first SWE application.

Compile and run the application on the device.

Understanding the WEST generated code.

Once WEST generates the code, you will see that there is a header file and C++ file created for each UserControl in the code. Observe the following generated files.

- MyFirstUserControl.cpp, MyFirstUserControl.h. You will see that the MyFirstUserControl class is derived from the template class XRCustomUserControlImpl<>.

clip_image008

If you look at the generated code the important pieces of code to notice are:

1. MyFirstUserControl class declaration:

If you look at the C# project generated using Blend, it will have a UserControl with name MainPage. The MainPage class in C# project would be derived from UserControl. If you look at MainPage.xaml.cs, you will find it in the code.

    1: public partial class MyFirstUserControl : UserControl
    2: {
    3:      public MyFirstUserControl ()
    4:      {
    5:          // Required to initialize variables
    6:          InitializeComponent();
    7:      }
    8: }

When you create a SWE project using csproj into Windows Embedded Silverlight Tools(WEST) , you will see a MyFirstUserControl C++ class created and is derived from the XRCustomUserControlImpl<> template class.

Notice that the MainPage class declaration is prefixed with __declspec() of a uuid. We need to do this so that the class pointer can be wrapped using the smart pointer XRPtr<Interface>

    1: // <UserControl x:Class="UserControlSample.MainPage">
    2: class __declspec(uuid("{64d102b8-555b-49f7-b43d-dd44166b8f14}")) 
    3:    MyFirstUserControl : public XRCustomUserControlImpl< MyFirstUserControl >
    4:  
    5:     QI_IDENTITY_MAPPING(MyFirstUserControl, XRCustomUserControlImpl)
    6:  
    7: public:
    8:     static HRESULT GetXamlSource(__in XRXamlSource* pXamlSource)
    9:     {
   10:         HRESULT hr = E_INVALIDARG;
   11:         if (pXamlSource)
   12:         {
   13:             pXamlSource->SetResource (App::GetHInstance(),IDR_USERCONTROLSAMPLECSHARP_MYFIRSTUSERCONTROL);
   14:             hr = S_OK;
   15:         }
   16:         return hr;
   17:     }
   18:     static HRESULT Register()
   19:     {
   20:         return XRCustomUserControlImpl<MyFirstUserControl>::Register (__uuidof(MyFirstUserControl), L"MyFirstUserControl", L"clr-namespace:UserControlSampleCSharp");
   21:     }
   22:     ...
   23:     ...
   24:     ...
   25: }

2. Registering the UserControl with the SWE runtime:

This step is not required in C# because the Silverlight C# runtime can create a type by using the power of reflection in C#.

But in SWE the programmer needs to explicitly let the runtime know the existence of the UserControl by registering the control with the runtime. This is done inside the MyFirstUserControl::Register() function.

In this function, the MyFirstUserControl class is registered with the SWE runtime using the class name, namespace and the UUID of the class.

    1: static HRESULT Register()
    2: {
    3:  return XRCustomUserControlImpl<MyFirstUserControl>::Register (__uuidof(MyFirstUserControl), L"MyFirstUserControl", L"clr-namespace:UserControlSampleCSharp");
    4: }

3. Associating the XAML with the code behind:

The XAML file needs to associated with the C++ class. This will be done inside the MyFirstUserControl::GetXamlSource() function.

When WEST generates the code, it marks the XAML files as resources in the project. In the MyFirstUserControl::GetXamlSource() function, this XAML resource is paired with the MyFirstUserControl UserControl.

    1: static HRESULT GetXamlSource(__in XRXamlSource* pXamlSource)
    2: {
    3:  HRESULT hr = E_INVALIDARG;
    4:  if (pXamlSource)
    5:  {
    6:      pXamlSource->SetResource (App::GetHInstance IDR_USERCONTROLSAMPLECSHARP_MYFIRSTUSERCONTROL);
    7:      hr = S_OK;
    8:  }
    9:  return hr;
   10: }
   11:  

4. Using an instance of MyFirstUserControl in the MainPage class:

In the sample above, the MainPage xaml contains an instance of MyFirstUserControl. But you will not find any code in the MainPage class that declares an instance of the UserControl. This is defined in the XAML directly. WEST does not create member variables for elements in the XAML that does not have x:Name associated with them. If we had given a name for the MyFirstUserControl inside the MainPage.xaml, WEST would have generated corresponding member variables.

In the next part of this tutorial, we will see how this can be done and also enhance the MyFirstUserControl to contain Dependency Properties and Attached Properties.

Stay tuned for Part 2.