Metro Style Apps Control Initialization in XAML/C# & HTML5/JS

Overview

Version: This article is being written on 06/21/2012 using Windows 8 Release Preview as a reference. 

In Windows 8 Metro Style apps you have a number of choices for your markup and programming languages  You can choose the XAML markup language with C#, VB.NET or even C++.  You now also have the choice of using HTML5 as your markup language along with JavaScript as the programming language. Both XAML and HTML5 provide a way for you to define object instances in a declarative way. 

When creating Metro Style apps with XAML, we declare instances of objects defined in the family of Windows.UI.Xaml.Controls namespaces, as well as some others.  These namespaces are provided as part of the WIndows API for Metro Style apps, They are included with the Windows SDK which is automatically referenced by the Visual Studio project templates.

When creating HTML5/JS Metro Style apps, you can use the HTML5 markup to define either standard HTML5 elements (div,span,input,button, etc).  These standard HTML5 elements are the EXACT same elements you would use in a browser based application. With HTML5/JS Metro Style apps can also declare control instances from the WinJS.UI namespaces provided by the Windows API for Metro Style apps (AppBar, Flyout, ViewBox, etc), . the project templates provided with Visual Studio automatically reference the “WinJS” library.  This library is provided with the Windows 8 SDK (C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0\ExtensionSDKs\Microsoft.WinJS.1.0.RC\1.0\).  The WinJS library is made up of a number of individual JavaScript files, but one in particular (ui.js) includes control definitions for the JavaScript WinJS.UI namespace.  These controls provided features similar to those provided in the Windows.UI.Xaml.Controls namespace used by XAML developers.

 


Control Declaration and Initialization in XAML Metro Style Apps

As an example, here is a Windows.UI.Xaml.Controls.Viewbox control declaration in a XAML document (note, this is just a document fragment)

<Viewbox x:Name="xamlViewbox"></Viewbox>

The line of XAML above declares a Viewbox instance named “xamlViewbox”.  To do the same thing in C#, I could do the following :

Viewbox csharpViewbox;

Both above examples DECLARE a Windows.UI.Xaml.Controls.Viewbox instance.  They don’t actually INITIALIZE them .  In c# for example, our csharpViewbox would not EXIST until we initialized it, or constructed it somehow.  For example:

csharpViewbox = new Viewbox();

Well, that’s fine for our controls defined in code, but for the controls that are defined in XAML, like our xamlViewbox above, they get initialized a slightly different way. The following assumes you are using Visual Studio as your development environment.  When you do a build in Visual Studio, it actually generates some code on your behalf behind the scenes.  In the constructor for your XAML document, the Visual Studio templates provide a call to a magical “InitializeComponent()” method. 

public sealed partial class MainPage : Page
{

  //Declare a Viewbox in code 
  Viewbox csharpViewbox;

  public MainPage()
  {
    //Objects declared in code can be initialized (constructed) normally 
    csharpViewbox = new Viewbox();

    //Objects declared in XAML get initialized differently....
    //Calls the Application.LoadComponet to initiaze the obje3cts declared in XAML
    //Then wires local names (like xamlViewbox) up to those objects
    this.InitializeComponent();
  }

  //... irrelevant code not shown

}

The InitializeComponent() method isn’t actually provided by the base class, but provided instead by Visual Studio as part of the build process.  If you go to the definition of the method (right click on the method name, and select “Go To Definition…”) you will see that the method is defined in the <PageName>.g.i.cs code file. In there, you’ll see a call to the Application.LoadComponent() method.  This method walks your XAML document, and creates object instances for each object declared in the XAML.  The method then wires your local variable up to the objects in the tree created by Application.LoadComponent().  Here is a commented version of the InitializeComponent method:

public void InitializeComponent()
{
  //Only load the content if it hasn't been loaded already
  if (_contentLoaded)
    return;

  //Mark the content as loaded so we don't load it again
  _contentLoaded = true;

  //Use the Application LoadComponent method to walk the XAML document and 
  //initialize (construct) each object declared in XAML.  
  //This puts the objects on the head
  Application.LoadComponent
    (this,
    new System.Uri("ms-appx:///MainPage.xaml"),
    Windows.UI.Xaml.Controls.Primitives.ComponentResourceLocation.Application);

  //map the local names (like xamlViewbox) up to the object references created in the 
  //LoadComponent method above
  xamlViewbox = (Windows.UI.Xaml.Controls.Viewbox)this.FindName("xamlViewbox");
}

Because of this you want to make sure that you don’t try to use any of the objects declared in XAML BEFORE the call to InitializeComponent(). 

Control Declaration and Initialization in HTML5/JS Metro Style Apps

WinJS.UI Control initialization in HTML5 apps is very similar to how control instances are initialized in XAML as described above.  There are some differences however.  First off all, your HTML5 documents will contain a mixture of standard HTML5 elements, as well as WinJS.UI controls.  The HTML5 elements are exposed to you via the DOM and you can use standard getElementByID() method calls to retrieve a reference to them, or the new standard querySelector and querySelectorAll methods, or heck or use libraries like jQuery if you prefer.

There are also however, the controls provied by the WinJS library and defined by the WinJS.UI namespace.  Those need to be initailized just like the XAML objects needed to be constructed above.  So again, let’s look at an example of the HTML5 markup method to declare a WinJS.UI.ViewBox:

<div id="html5ViewBox" data-win-control="WinJS.UI.ViewBox"></div>

Again, we could declare controls in JavaScript code:

var jsViewBox;

But just like our XAML/C# example above these controls are declared, but not initialized.  We could initialize our JavaScript variable like this:

jsViewBox = new WinJS.UI.ViewBox();

For the controls declared in HTML5 markup however, they don’t get initialized until the WinJS.UI.processAll() is called. The templates provided by Visual Studio automatically call the WinJS.UI.processAll() method for you from initial HTML5 document’s app.onactivated function.

app.onactivated = function (args) {
  if (args.detail.kind === activation.ActivationKind.launch) {
    if (args.detail.previousExecutionState !== activation.ApplicationExecutionState.terminated) {
      // TODO: This application has been newly launched. Initialize
      // your application here.
    } else {
      // TODO: This application has been reactivated from suspension.
      // Restore application state here.
    }
    args.setPromise(WinJS.UI.processAll());
  }
};

Unlike the InitalizeComponent() method described above for XAML documents, the WinJS.UI.processAll() method is NOT generated on the fly.  It is provided as part of the WinJS library and exists in the base.js file.  Its job is similar however.  It walks your HTML5 documents and retrieves all elements marked with the “data-win-control” attribute.  It then resolves the type of the control from the attribute and instantiates it. 

processAll: function (rootElement) {
    /// <signature helpKeyword="WinJS.UI.processAll">
    /// <summary locid="WinJS.UI.processAll">
    /// Applies declarative control binding to all elements, starting at the specified root element.
    /// </summary>
    /// <param name="rootElement" type="Object" domElement="true" locid="WinJS.UI.processAll_p:rootElement">
    /// The element at which to start applying the binding. If this parameter is not specified, the binding is applied to the entire document.
    /// </param>
    /// <returns type="WinJS.Promise" locid="WinJS.UI.processAll_returnValue">
    /// A promise that is fulfilled when binding has been applied to all the controls.
    /// </returns>
    /// </signature>

    if (!processedAllCalled) {
        return WinJS.Utilities.ready().then(function () {
            processedAllCalled = true;
            return processAllImpl(rootElement);
        });
    }
    else {
        return processAllImpl(rootElement);
    }
}

While you would be able to retrieve the HTML5 element for the control, the actual WinJS.UI control functionality wouldn’t exist until the call to WinJS.UI.processAll() has completed.  Once it has though, you can then get to the control features by first retrieving the element by it’s ID, and then accessing the .winControl property on it.

var h5Vb = document.querySelector("#html5ViewBox").winControl;

Summary

Metro style app development is made up of both declarative, imperative, and functional programming styles.  When we declare controls in code, it is easy to see when controls are both declared as well as when they are initialized.  When we define objects in a declarative way using either XAML or HTML5, it is necessary for initialization to occur before we can interact with the controls.  In this article I showed how initialization occurs in both XAML and HTML5 Metro Style apps.

Leave a Reply