Chapter 4
Controls, Control Styling, and Data Binding

Controls are one of those things you just can’t seem to get away from, especially within technology-addicted cultures like those that surround many of us. Even low-tech devices like bicycles and various gardening tools have controls. But this isn’t a problem—it’s actually a necessity. Controls are the means through which human intent is translated into the realm of mechanics and electronics, and they are entirely made to invite interaction. As I write this, in fact, I’m sitting on an airplane and noticing all the controls that are in my view. The young boy in the row ahead of me seems to be doing the same, and that big “call attendant” button above him is just begging to be pressed!

Controls are certainly essential to Windows 8 apps, and they will invite consumers to poke, prod, touch, click, and swipe them. (They will also invite the oft-soiled hands of many small toddlers as well; has anyone made a dishwasher-safe tablet PC yet?) Windows 8, of course, provides a rich set of controls for apps written in HTML, CSS, and JavaScript. What’s most notable in this context is that from the earliest stages of design, Microsoft wanted to avoid forcing HTML/JavaScript developers to use controls that were incongruous with what those developers already know—namely, the use of HTML control elements like <button> that can be styled with CSS and wired up in JavaScript by using functions like addEventListener and on<event> properties.

You can, of course, use those intrinsic HTML controls in a Windows 8 app because those apps run on top of the same HTML/CSS rendering engine as Internet Explorer. No problem. There are even special classes, pseudo-classes, and pseudo-elements that give you fine-grained styling capabilities, as we’ll see. But the real question was how to implement Windows 8-specific controls like the toggle switch and list view that would allow you to work with them in the same way—that is, declare them in markup, style them with CSS, and wire them up in JavaScript with addEventListener and on<event> properties.

The result of all this is that for you, the HTML/JavaScript developer, you’ll be looking to WinJS for these controls rather than WinRT. Let me put it another way: if you’ve noticed the large collection of APIs in the Windows.UI.Xaml namespace (which constitutes about 40% of WinRT), guess what? You get to completely ignore all of it! Instead, you’ll use the WinJS controls that support declarative markup, styling with CSS, and so on, which means that Windows controls (and custom controls that follow the same model) ultimately show up in the DOM along with everything else, making them accessible in all the ways you already know and understand.

The story of controls in Windows 8 is actually larger than a single chapter. Here we’ll be looking primarily at those controls that represent or work with simple data (single values) and that participate in page layout as elements in the DOM. Participating in the DOM, in fact, is exactly why you can style and manipulate all the controls (HTML and WinJS alike) through standard mechanisms, and a big part of this chapter is to just visually show the styling options you have available. In the latter part of this chapter we’ll also explore the related subject of data binding: creating relationships between properties of data objects and properties of controls (including styles) so that the controls reflect what’s happening in the data.

The story will then continue in Chapter 5, “Collections and Collection Controls,” where we’ll look at collection controls—those that work with potentially large data sets—and the additional data-binding features that go with them. We’ll also give special attention to media elements (image, audio, and video) in Chapter 10, aptly titled “Media,” as they have a variety of unique considerations. Similarly, those elements that are primary for defining layout (like grid and flexbox) are the subject of Chapter 6, “Layout,” and we also have a number of UI elements that don’t participate in layout at all, like app bars and flyouts, as we’ll see in Chapter 7, “Commanding UI.”

In short, having covered much of the wiring, framing, and plumbing of an app in Chapter 3, “App Anatomy and Page Navigation,” we’re ready to start enjoying the finish work like light switches, doorknobs, and faucets—the things that make an app really come to life and engage with human beings.

Before we go on, you’ll want to know about two essential topics on the Windows Developer Center that you’ll likely refer to time and time again. First is the comprehensive Controls list that identifies all the controls that are available to you, as we’ll summarize later in this chapter. The second are comprehensive UX Guidelines for Windows 8 apps, which describes the best use cases for most controls and scenarios in which not to use them. This is a very helpful resource for both you and your designers.

The Control Model for HTML, CSS, and JavaScript

Again, when Microsoft designed the developer experience for Windows 8, we strove for a high degree of consistency between intrinsic HTML control elements, WinJS controls, and custom controls. I like to refer to all of these as “controls” because they all result in a similar user experience: some kind of widget with which the user interacts with an app. In this sense, every such control has three parts:

• Declarative markup (producing elements in the DOM)

• Applicable CSS (styles as well as special pseudo-class and pseudo-element selectors)

• Methods, properties, and events accessible through JavaScript

Standard HTML controls, of course, already have dedicated markup to declare them, like <button>, <input>, and <progress>. WinJS and custom controls, lacking the benefit of existing standards, are declared using some root element, typically a <div> or <span>, with two custom data-* attributes: data-win-control and data-win-options. The value of data-win-control specifies the fully qualified name of a public constructor function that creates the actual control as child elements of the root. The second, data-win-options, is a JSON string containing key-value pairs separated by commas: { <key1>: <value1>, <key1>: <value2>, ... }.

Hint If you’ve just made changes to data-win-options and your app seems to terminate without reason (and without an exception) when you next launch it, check for syntax errors in the options string. Forgetting the closing }, for example, will cause this behavior.

The constructor function itself takes two parameters: the root (parent) element and an options object. Conveniently, WinJS.Class.define produce functions that look exactly like this, making it very handy for defining controls (as WinJS does itself). Of course, because data-* attributes are, according to the HTML5 specifications, completely ignored by the HTML/CSS rendering engine, some additional processing is necessary to turn an element with these attributes into an actual control in the DOM. And this, as I’ve hinted at before, is exactly the life purpose of the WinJS.UI.process and WinJS.UI.processAll methods. As we’ll see shortly, these methods parse the options attribute and pass the resulting object and the root element to the constructor function identified in data-win-control.

The result of this simple declarative markup plus WinJS.UI.process/processAll is that WinJS and custom controls are just elements in the DOM like any others. They can be referenced by DOM-traversal APIs and targeted for styling using the full extent of CSS selectors (as we’ll see in the styling gallery later on). They can listen for external events like other elements and can surface events of their own by implementing [add/remove]EventListener and on<event> properties. (WinJS again provides standard implementations of addEventListener, removeEventListener, and dispatchEvent for this purpose.)

Let’s now look at the controls we have available for Windows 8 apps, starting with the HTML controls and then the WinJS controls. In both cases we’ll look at their basic appearance, how they’re instantiated, and the options you can apply to them.

HTML Controls

HTML controls, I hope, don’t need much explaining. They are described in HTML5 references, such as http://www.w3schools.com/html5/html5_reference.asp, and shown with default “light” styling in Figure 4-1 and Figure 4-2. (See the next section for more on WinJS stylesheets.) It’s worth mentioning that most embedded objects are not supported, except for a specific ActiveX controls; see Migrating a web app.

Creating or instantiating HTML controls works as you would expect. You can declare them in markup by using attributes to specify options, the rundown of which is given in the table following Figure 4-2. You can also create them procedurally from JavaScript by calling new with the appropriate constructor, configuring properties and listeners as desired, and adding the element to the DOM wherever its needed. Nothing new here at all where Windows 8 apps are concerned.

For examples of creating and using these controls, refer to the HTML essential controls sample in the Windows SDK, from which the images in Figure 4-1 and Figure 4-2 were obtained.

Image

FIGURE 4-1 Standard HTML5 controls with default “light” styles (the ui-light.css stylesheet of WinJS).

Image

FIGURE 4-2 Standard HTML5 text input controls with default “light” styles (the ui-light.css stylesheet of WinJS).

Image

Two areas that add something to HTML controls are the WinJS stylesheets and the additional methods, properties, and events that Microsoft’s rendering engine adds to most HTML elements. These are the subjects of the next two sections.

WinJS stylesheets: ui-light.css, ui-dark.css, and win-* styles

WinJS comes with two parallel stylesheets that provide many default styles and style classes for Windows Store apps: ui-light.css and ui-dark.css. You’ll always use one or the other, as they are mutually exclusive. The first is intended for apps that are oriented around text, because dark text on a light background is generally easier to read (so this theme is often used for news readers, books, magazines, etc., including figures in published books like this!). The dark theme, on the other hand, is intended for media-centric apps like picture and video viewers where you want the richness of the media to stand out.

Both stylesheets define a number of win-* style classes, which I like to think of as style packages that effectively add styles and CSS-based behaviors (like the :hover pseudo-class) that turn standard HTML controls into a Windows 8-specific variant. These are win-backbutton for buttons, win-ring, win-medium, and win-large for circular progress controls, win-small for a rating control, win-vertical for a vertical slider (range) control, and win-textarea for a content editable div. If you want to see the details, search on their names in the Style Rules tab in Blend.

Extensions to HTML Elements

As you probably know already, there are many developing standards for HTML and CSS. Until these are brought to completion, implementations of those standards in various browsers are typically made available ahead of time with vendor-prefixed names. In addition, browser vendors sometimes add their own extensions to the DOM API for various elements.

With Windows Store apps, of course, you don’t need to worry about the variances between browsers, but since these apps essentially run on top of the Internet Explorer engine, it helps to know about those extensions that still apply. These are summarized in the table below, and you can find the full Elements reference in the documentation for all the details your heart desires (and too much to spell out here).

If you’ve been working with HTML5 and CSS3 in Internet Explorer already, you might be wondering why the table doesn’t show the various animation (msAnimation*), transition (msTransition*), and transform properties (msPerspective* and msTransformStyle), along with msBackfaceVisibility. This is because these standards are now far enough along that they no longer need vendor prefixes with Internet Explorer 10 or Store apps (though the ms* variants still work).

Image

WinJS Controls

Windows 8 defines a number of controls that help apps fulfill Windows app design guidelines. As noted before, these are implemented in WinJS for apps written in HTML, CSS, and JavaScript, rather than WinRT; this allows those controls to integrate naturally with other DOM elements. Each control is defined as part of the WinJS.UI namespace using WinJS.Class.define, where the constructor name matches the control name. So the full constructor name for a control like the Rating is WinJS.UI.Rating.

The simpler controls that we’ll cover here in this chapter are DatePicker, Rating, ToggleSwitch, and Tooltip, the default styling for which are shown in Figure 4-3. The collection controls that we’ll cover in Chapter 5 are FlipView, ListView, and SemanticZoom. App bars, flyouts, and others that don’t participate in layout are again covered in later chapters. Apart from these, there is only one other, HtmlControl, which is simply an older (and essentially deprecated) alias for WinJS.UI.Pages. That is, the HtmlControl is the same thing as rendering a page control: it’s an arbitrary block of HTML, CSS, and JavaScript that you can declaratively incorporate anywhere in a page. We’ve already discussed all those details in Chapter 3, so there’s nothing more to add here.

Image

FIGURE 4-3 Default (light) styles on the simple WinJS controls.

The WinJS.UI.Tooltip control, you should know, can utilize any HTML including other controls, so it goes well beyond the plain text tooltip that HTML provides automatically for the title attribute. We’ll see more examples later.

So again, a WinJS control is declared in markup by attaching data-win-control and data-win-options attributes to some root element. That element is typically a div (block element) or span (inline element), because these don’t bring much other baggage, but any element can be used. These elements can, of course, have id and class attributes as needed. The available options for these controls are summarized in the table below, which includes those events that can be wired up through the data-win-options string, if desired. For full documentation on all these options, start with the Controls list in the documentation and go to the control-specific topics linked from there.

Image

Again, the data-win-options string containing key-value pairs, one for each property or event, separated by commas, in the form { <key1>: <value1>, <key1>: <value2>, ... }. For events, whose names in the options string always start with on, the value is the name of the event handler you want to assign.

In JavaScript code, you can also assign event handlers by using <element>.addEventListener ("<event>", ...) where <element> is the element for which the control was declared and <event> drops the “on” as usual. To access the properties and events directly, use <element>.winControl.<property>. The winControl object is created when the WinJS control is instantiated and attached to the element, so that’s where these options are available.

WinJS Control Instantiation

As we’ve seen a number of times already, WinJS controls declared in markup with data-* attributes are not instantiated until you call WinJS.UI.process(<element>) for a single control or WinJS.UI.-processAll for all such elements in the DOM. To understand this process, here’s what WinJS.UI.-process does for a single element:

1. Parse the data-win-options string into an options object.

2. Extract the constructor specified in data-win-control and call new on that function passing the root element and the options object.

3. The constructor creates whatever child elements it needs within the root element.

4. The object returned from the constructor—the control object—is stored in the root element’s winControl property.

Clearly, then, the bulk of the work really happens in the constructor. Once this takes place, other JavaScript code (as in your activated method) can call methods, manipulate properties, and add listeners for events on both the root element and the winControl object. The latter, clearly, must be used for WinJS control-specific methods, properties, and events.

WinJS.UI.processAll, for its part, simply traverses the DOM looking for data-win-control attributes and does WinJS.UI.process for each. How you use both of these is really your choice: processAll goes through a whole page (or just a page control—whatever the document object refers to), whereas process lets you control the exact sequence or instantiate controls for which you dynamically insert markup. Note that in both cases the return value is a promise, so if you need to take additional steps after processing is complete, provide a completed handler to the promise’s done method.

It’s also good to understand that process and processAll are really just helper functions. If you need to, you can just directly call new on a control constructor with an element and options object. This will create the control and attach it to the given element automatically. You can also pass null for the element, in which case the WinJS control constructors create a new div element to contain the control that is otherwise unattached to the DOM. This would allow you, for instance, to build up a control offscreen and attach it to the DOM only when needed.

To see all this in action, we’ll look at some examples with both the Rating and Tooltip controls in a moment. First, however, we need to discuss a matter referred to as strict processing.

Strict Processing and processAll Functions

WinJS has three DOM-traversing functions: WinJS.UI.processAll, WinJS.Binding.processAll (which we’ll see later in this chapter), and WinJS.Resources.processAll (which we’ll see in Chapter 17, “Apps for Everyone”). Each of these looks for specific data-win-* attributes and then takes additional actions using those contents. Those actions, however, can involve calling a number of different types of functions:

• Functions appearing in a “dot path” for control processing and binding sources

• Functions appearing in the left-hand side for binding targets, resource targets, or control processing

• Control constructors and event handlers

• Binding initializers or functions used in a binding expression

• Any custom layout used for a ListView control

Such actions introduce a risk of injection attack if a processAll function is called on untrusted HTML, such as arbitrary markup obtained from the web. To mitigate this risk, WinJS has a notion of strict processing that is enforced within all HTML/JavaScript apps. The effect of strict processing is that any functions indicated in markup that processAll methods might encounter must be “marked for processing” or else processing will fail. The mark itself is simply a property named supportedFor-Processing on the function object that is set to true.

Functions returned from WinJS.Class.define, WinJS.Class.derive, WinJS.UI.Pages.define, and WinJS.Binding.converter are automatically marked in this manner. For other functions, you can either set a supportedForProcessing property to true directly or use any of the following marking functions:

WinJS.Utilities.markSupportedForProcessing(myfunction);
WinJS.UI.eventHandler(myHandler);
WinJS.Binding.initializer(myInitializer);

//Also OK
<namespace>.myfunction = WinJS.UI.eventHandler(function () {
});

Note also that appropriate functions coming directly from WinJS, such as all WinJS.UI.* control constructors, as well as WinJS.Binding.* functions, are marked by default.

So, if you reference custom functions from your markup, be sure to mark them accordingly. But this is only for references from markup: you don’t need to mark functions that you assign to on<event> properties in JavaScript or pass to addEventListener.

Example: WinJS.UI.Rating Control

OK, now that we got the strict processing stuff covered, let’s see some concrete examples of working with a WinJS control.

For starters, here’s some markup for a WinJS.UI.Rating control, where the options specify two initial property values and an event handler:

<div id="rating1" data-win-control="WinJS.UI.Rating"
    data-win-options="{averageRating: 3.4, userRating: 4, onchange: changeRating}">
</div>

To instantiate this control, we need either of the following calls:

WinJS.UI.process(document.getElementById("rating1"));
WinJS.UI.processAll();

Again, both of these functions return a promise, but it’s unnecessary to call done unless we need to do additional post-instantiation processing or handle exceptions that might have occurred (and that are otherwise swallowed). Also, note that the changeRating function specified in the markup must be globally visible and marked for processing, or else the control will fail to instantiate.

Alternately, we can instantiate the control and set the options procedurally. In markup:

<div id="rating1" data-win-control="WinJS.UI.Rating"></div>

And in code:

var element = document.getElementById("rating1");
WinJS.UI.process(element);
element.winControl.averageRating = 3.4;
element.winControl.userRating = 4;
element.winControl.onchange = changeRating;

The last three lines above could also be written as follows using the WinJS.UI.setOptions method, but this isn’t recommended because it’s harder to debug:

var options = { averageRating: 3.4, userRating: 4, onchange: changeRating };
WinJS.UI.setOptions(element.winControl, options);

We can also just instantiate the control directly. In this case the markup is nonspecific:

<div id="rating1"></div>

and we call new on the constructor ourselves:

var newControl = new WinJS.UI.Rating(document.getElementById("rating1"));
newControl.averageRating = 3.4;
newControl.userRating = 4;
newControl.onchange = changeRating;

Or, as mentioned before, we can skip the markup entirely, have the constructor create an element for us (a div), and attach it to the DOM at our leisure:

var newControl = new WinJS.UI.Rating(null,
    { averageRating: 3.4, userRating: 4, onchange: changeRating });
newControl.element.id = "rating1";
document.body.appendChild(newControl.element);

Hint If you see strange errors on instantiation with these latter two cases, check whether you forgot the new and are thus trying to directly invoke the constructor function.

Note also in these last two cases that the rating1 element will have a winControl property that is the same as the newControl returned from the constructor.

To see this control in action, please refer to the HTML Rating control sample.

Example: WinJS.UI.Tooltip Control

With most of the other simple controls—namely the DatePicker, TimePicker, and ToggleSwitch—you can work with them in the same ways as we just saw with Ratings. All that changes are the specifics of their properties and events; again, start with the Controls list page and navigate to any given control for all the specific details. Also, for working samples refer to the HTML DatePicker and TimePicker controls and the HTML ToggleSwitch control samples.

The WinJS.UI.Tooltip control is a little different, however, so I’ll illustrate its specific usage. First, to attach a tooltip to a specific element, you can either add a data-win-control attribute to that element or place the element itself inside the control:

<!-- Directly attach the Tooltip to its target element -->
<targetElement data-win-control="WinJS.UI.Tooltip">
</targetElement>

<!-- Place the element inside the Tooltip -->
<span data-win-control="WinJS.UI.Tooltip">
    <!-- The element that gets the tooltip goes here -->
</span>

<div data-win-control="WinJS.UI.Tooltip">
    <!-- The element that gets the tooltip goes here -->
</div>

Second, the contentElement property of the tooltip control can name another element altogether, which will be displayed when the tooltip is invoked. For example, consider this piece of hidden HTML in our markup thatcontains other controls:

<div style="display: none;">
    <!--Here is the content element. It's put inside a hidden container
    so that it's invisible to the user until the tooltip takes it out.-->
    <div id="myContentElement">
        <div id="myContentElement_rating">
            <div data-win-control="WinJS.UI.Rating" class="win-small movieRating"
                data-win-options="{userRating: 3}">
            </div>
        </div>
        <div id="myContentElement_description">
            <p>You could provide any DOM element as content, even with WinJS controls inside. The tooltip control
will re-parent the element to the tooltip container, and block interaction events on that element, since that's
not the suggested interaction model.</p>
        </div>
        <div id="myContentElement_picture">
        </div>
    </div>
</div>

We can reference it like so:

<div data-win-control="WinJS.UI.Tooltip"
    data-win-options="{infotip: true, contentElement: myContentElement}">
    <span>My piece of data</span>
</div>

When you hover over the text (with a mouse or hover-enabled touch hardware), this tooltip will appear:

Image

This example is taken directly from the HTML Tooltip control sample, so you can go there to see how all this works directly.

Working with Controls in Blend

Before we move onto the subject of control styling, it’s a good time to highlight a few additional features of Blend for Visual Studio where controls are concerned. As I mentioned in Video 2-2, the Assets tab in Blend gives you quick access to all the HTML elements and WinJS controls (among many other elements) that you can just drag and drop into whatever page is showing in the artboard. (See Figure 4-4.) This will create basic markup, such as a div with a data-win-control attribute for WinJS controls; then you can go to the HTML Attributes pane (on the right) to set options in the markup. (See Figure 4-5.)

Image

FIGURE 4-4 HTML elements (left) and WinJS control (right) as shown in Blend’s Assets tab.

Image

FIGURE 4-5 Blend’s HTML Attributes tab shows WinJS control options, and editing them will affect the data-win-options attribute in markup.

Next, take a moment to load up the HTML essential controls sample into Blend. This is a great opportunity to try out Blend’s Interactive Mode to navigate to a particular page and explore the interaction between the artboard and the Live DOM. (See Figure 4-6.) Once you open the project, go into interactive mode by selecting View -> Interactive Mode on the menu, pressing Ctrl+Shift+I, or clicking the small leftmost button on the upper right corner of the artboard. Then select Scenario 5 (Progress introduction) in the listbox, which will take you to the page shown in Figure 4-6. Then exit interactive mode (same commands), and you’ll be able to click around on that page. A short demonstration of using interactive mode in this way is given in Video 4-1 in this chapter’s companion content.

Image

FIGURE 4-6 Blend’s interaction between the artboard and the Live DOM.

With the HTML essential controls sample, you’ll see that there’s just a single element in the Live DOM for intrinsic controls, as there should be, since all the internal details are part and parcel of the HTML/CSS rendering engine. On the other hand, load up the HTML Rating control sample instead and expand the div that contains one such control. There you’ll see all the additional child elements that make up this control (shown in Figure 4-7), and you can refer to the right-hand pane for HTML attributes and CSS properties. You can see something similar (with even more detailed information), in the DOM Explorer of Visual Studio when the app is running. (See Figure 4-8.)

Image

FIGURE 4-7 Expanding a WinJS control in Blend’s Live DOM reveals the elements that are used to build it.

Image

FIGURE 4-8 Expanding a WinJS control in Visual Studio’s DOM Explorer also shows complete details for a control.

Control Styling

Now we come to a topic where we’ll mostly get to look at lots of pretty pictures: the various ways in which HTML and WinJS controls can be styled. As we’ve discussed, this happens through CSS all the way, either in a stylesheet or by assigning style.* properties, meaning that apps have full control over the appearance of controls. In fact, absolutely everything that’s different between HTML controls in a Store app and the same controls on a web page is due to styling and styling alone.

For both HTML and WinJS controls, CSS standards apply including pseudo-selectors like :hover, :active, :checked, and so forth, along with -ms-* prefixed styles for emerging standards.

For HTML controls, there are also additional -ms-* styles—that aren’t part of CSS3—to isolate specific parts of those controls. That is, because the constituent parts of such controls don’t exist separately in the DOM, pseudo-selectors—like ::-ms-check to isolate a checkbox mark and ::-ms-fill-lower to isolate the left or bottom part of a slider—allow you to communicate styling to the depths of the rendering engine. In contrast, all such parts of WinJS controls are addressable in the DOM, so they are just styled with specific win-* classes defined in the WinJS stylesheets. That is, the controls are simply rendered with those style classes. Default styles are defined in the WinJS stylesheets, but apps can override any aspect of those to style the controls however you want.

In a few cases, as already pointed out, certain win-* classes define style packages for use with HTML controls, such as win-backbutton, win-vertical (for a slider) and win-ring (for a progress control). These are intended to style standard controls to look like special system controls.

There are also a few general purpose -ms-* styles (not selectors) that can be applied to many controls (and elements in general), along with some general WinJS win-* style classes. These are summarized in the following table.

Image

For all of these and more, spend some time with these three reference topics: WinJS CSS classes for typography, WinJS CSS classes for HTML controls, and CSS classes for WinJS controls. I also wanted to provide you with a summary of all the other vendor-prefixed styles (or selectors) that are supported within the CSS engine for Store apps; see the next table. Vendor-prefixed styles for animations, transforms, and transitions are still supported, though no longer necessary, because these standards have recently been finalized. I made this list because the documentation here can be hard to penetrate: you have to click through the individual pages under the Cascading Style Sheets topic in the docs to see what little bits have been added to the CSS you already know.

Image

Styling Gallery: HTML Controls

Now we get to enjoy a visual tour of styling capabilities for Windows Store apps. Much can be done with standard styles, and then there are all the things you can do with special styles and classes as shown in the graphics in this section. The specifics of all these examples can be seen in the HTML essential controls sample.

Also check out the very cool Applying app theme color (theme roller) sample. This beauty lets you configure the primary and secondary colors for an app, shows how those colors affect different controls, and produces about 200 lines of precise CSS that you can copy into your own stylesheet. This very much helps you create a color theme for your app, which we very much encourage to establish an app’s own personality within the overall Windows 8 design guidelines and not try to look like the system itself. (Do note that controls in system-provided UI, like the confirmation flyout when creating secondary tiles, will be styled with system colors. These cannot be controlled by the app.)

Image

Image

Image

Image

Image

Note Though not shown here, you can also use the -ms-scrollbar-* styles for scrollbars that appear on pannable content in your app.

Styling Gallery: WinJS Controls

Similarly, here is a visual rundown of styling for WinJS controls, drawing again from the samples in the SDK: HTML DatePicker and TimePicker controls, HTML Rating control, HTML ToggleSwitch control, and HTML Tooltip control.

For the WinJS DatePicker and TimePicker, refer to styling for the HTML select element along with the ::-ms-value and ::-ms-expand pseudo-elements. I will note that the sample isn’t totally comprehensive, so the visuals below highlight the finer points:

Image

Image

The Rating control has states that can be styled in addition to its stars and the overall control. win-* classes identify these individually; combinations style all the variations as in this table:

Image

Image

For the ToggleSwitch, win-* classes identify parts of the control; states are implicit. Note that the win-switch part is just an HTML slider control (<input type="range">), so you can utilize all the pseudo-elements for its parts.

Image

And finally, for Tooltip, win-tooltip is a single class for the tooltip as a whole; the control can then contain any other HTML to which CSS applies using normal selectors:

Image

Image

Some Tips and Tricks

• In the current implementation, tooltips on a slider (<input type="range">) are always numerical values; there isn’t a means to display other forms of text, such as Low, Medium, and High. For something like this, you could consider a WinJS.UI.Rating control with three values, using the tooltipStrings property to customize the tooltips.

• The ::-ms-tooltip pseudo-selector for the slider affects only visibility (with display: none); it cannot be used to style the tooltip generally. This is useful to hide the default tooltips if you want to implement custom UI of your own.

• There are additional types of input controls (different values for the type attribute) that I haven’t mentioned. This is because those types have no special behaviors and just render as a text box. Those that have been specifically identified might also just render as a text box, but they can affect, for example, what on-screen keyboard configuration is displayed on a touch device (see Chapter 9) and also provide specific input validation (e.g., the number type only accepts digits).

• The WinJS attribute, data-win-selectable, when set to true, specifies that an element is selectable in the same way that all input and contenteditable elements are.

• If you don’t find width and height properties working for a control, try using style.width and style.height instead.

• You’ll notice that there are two kinds of button controls: <button> and <input type="button">. They’re visually the same, but the former is a block tag and can display HTML inside itself, whereas the latter is an inline tag that displays only text. A button also defaults to <input type="submit">, which has its own semantics, so you generally want to use <button type="button"> to be sure.

• If a WinJS.UI.Tooltip is getting clipped, you can override the max-width style in the win-tooltip class, which is set to 30em in the WinJS stylesheets. Again, peeking at the style in Blend’s Style Rules tab is a quick way to see the defaults.

• The HTML5 meter element is not supported for Store apps.

• There’s a default dotted outline for a control when it has the focus (tabbing to it with the keyboard or calling the focus method in JavaScript). To turn off this default rectangle for a control, use <selector>:focus { outline: none; } in CSS.

• Store apps can use the window.getComputedStyle method to obtain a currentStyle object that contains the applied styles for an element, or for a pseudo-element. This is very helpful, especially for debugging, because pseudo-elements like ::-ms-thumb for an HTML slider control never appear in the DOM, so the styling is not accessible through the element’s style property nor does it surface in tools like Blend. Here’s an example of retrieving the background color style for a slider thumb:

    var styles = window.getComputedStyle(document.getElementById("slider1"), "::-ms-thumb");
    styles.getPropertyValue("background-color");

Custom Controls

As extensive as the HTML and WinJS controls are, there will always be something you wish the system provided but doesn’t. “Is there a calendar control?” is a question I’ve often heard. “What about charting controls?” These clearly aren’t included directly in Windows 8, and despite any wishing to the contrary, it means you or another third-party will need to create a custom control.

Fortunately, everything we’ve learned so far, especially about WinJS controls, applies to custom controls. In fact, WinJS controls are entirely implemented using the same model that you can use directly, and since you can look at the WinJS source code anytime you like, you already have a bunch of reference implementations available.

To go back to our earlier definition, a control is just declarative markup (creating elements in the DOM) plus applicable CSS, plus methods, properties, and events accessible from JavaScript. To create such a control in the WinJS model, follow this general pattern:

1. Define a namespace for your control(s) by using WinJS.Namespace.define to both provide a naming scope and to keep excess identifiers out of the global namespace. (Do not add controls to the WinJS namespace.) Remember that you can call WinJS.Namespace.define many times to add new members, so typically an app will just have a single namespace for all its custom controls.

2. Within that namespace, define the control constructor by using WinJS.Class.define (or derive), assigning the return value to the name you want to use in data-win-control attributes. That fully qualified name will be <namespace>.<constructor>.

3. Within the constructor (of the form <constructor>(element, options)):

a. You can recognize any set of options you want; these are arbitrary. Simply ignore any that you don’t recognize.

b. If element is null or undefined, create a div to use in its place.

c. Assuming element is the root element containing the control, be sure to set element.winControl=this and this.element=element to match the WinJS pattern.

4. Within WinJS.Class.define, the second argument is an object containing your public methods and properties (those accessible through an instantiated control instance); the third argument is an object with static methods and properties (those accessible through the class name without needing to call new).

5. For your events, mix (WinJS.Class.mix) your class with the results from WinJS.Utilities.-createEventProperties(<events>) where <events> is an array of your event names (without on prefixes). This will create on<event> properties in your class for each name in the list.

6. Also mix your class with WinJS.UI.DOMEventMixin to add standard implementations of addEventListener, removeEventListener, dispatchEvent, and setOptions.28

7. In your implementation (markup and code), refer to classes that you define in a default stylesheet but that can be overridden by consumers of the control. Consider using existing win-* classes to align with general styling.

8. A typical best practice is to organize your custom controls in per-control folders that contain all the html, js, and css files for that control. Remember also that calls to WinJS.Namespace.define for the same namespace are additive, so you can populate a single namespace with controls that are defined in separate files.

You might consider using WinJS.UI.Pages if what you need is mostly a reusable block of HTML/CSS/JavaScript for which you don’t necessarily need a bunch of methods, properties, and events. WinJS.UI.Pages is, in fact, implemented as a custom control. Along similar lines, if what you need is a reusable block of HTML in which you want to do run-time data binding, check out WinJS.Binding.-Template, which we’ll see toward the end of this chapter. This isn’t a control as we’ve been describing here—it doesn’t support events, for instance—but might be exactly what you need.

It’s also worth reminding you that everything in WinJS, like WinJS.Class.define and WinJS.UI.-DOMEventMixin are just helpers for common patterns. You’re not in any way required to use these, because in the end, custom controls are just elements in the DOM like any others and you can create and manage them however you like. The WinJS utilities just make most jobs cleaner and easier.

Custom Control Examples

To see these recommendations in action, here are a couple of examples. First is what Chris Tavares, one of the WinJS engineers who has been a tremendous help with this book, described as the “dumbest control you can imagine.” Yet it certainly shows the most basic structures:

WinJS.Namespace.define("AppControls", {
    HelloControl: WinJS.Class.define(function (element, options) {
        element.winControl = this;
        this.element = element;

        if (options.message) {
            element.innerText = options.message;
        }
    })
});

With this, you can then use the following markup so that WinJS.UI.process/processAll will instantiate an instance of the control (as an inline element because we’re using span as the root):

<span data-win-control="AppControls.HelloControl"
    data-win-options="{ message: 'Hello, World'}">
</span>

Note that the control definition code must be executed before WinJS.UI.process/processAll so that the constructor function named in data-win-control actually exists at that point.

For a more complete control, you can take a look at the HTML SemanticZoom for custom controls sample. My friend Kenichiro Tanaka of Microsoft Tokyo also created the calendar control shown in Figure 4-9 and provided in the CalendarControl example for this chapter. (Note that this is example is only partly sensitive to localized calendar settings; it is not meant to be full-featured.)

Following the guidelines given earlier, this control is defined using WinJS.Class.define within a Controls namespace (calendar.js lines 4–10 shown here [with a comment line omitted]):

WinJS.Namespace.define("Controls", {
    Calendar : WinJS.Class.define(
        function (element, options) {
            this.element = element || document.createElement("div");
            this.element.className = "control-calendar";
            this.element.winControl = this;

The rest of the constructor (lines 12–63) builds up the child elements that define the control, making sure that each piece has a particular class name that, when scoped with the control-calendar class placed on the root element above, allows specific styling of the individual parts. The defaults for this are in calendar.css; specific overrides that differentiate the two controls in Figure 4-9 are in default.css.

Image

FIGURE 4-9 Output of the Calendar Control example.

Within the constructor you can also see that the control wires up its own event handlers for its child elements, such as the previous/next buttons and each date cell. In the latter case, clicking a cell uses dispatchEvent to raise a dateselected event from the overall control itself.

Lines 63–127 then define the members of the control. There are two internal methods, _setClass and _update, followed by two public methods, nextMonth and prevMonth, followed by three public properties, year, month, and date. Those properties can be set through the data-win-options string in markup or directly through the control object as we’ll see in a moment.

At the end of calendar.js you’ll see the two calls to WinJS.Class.mix to add properties for the events (there’s only one here), and the standard DOM event methods like addEventListener, removeEventListener, and dispatchEvent, along with setOptions:

WinJS.Class.mix(Controls.Calendar, WinJS.Utilities.createEventProperties("dateselected"));
WinJS.Class.mix(Controls.Calendar, WinJS.UI.DOMEventMixin);

Very nice that adding all these details is so simple—thank you, WinJS!29

Between calendar.js and calendar.css we have the definition of the control. In default.html and default.js we can then see how the control is used. In Figure 4-9, the control on the left is declared in markup and instantiated through the call to WinJS.UI.processAll in default.js.

<div id="calendar1" class="control-calendar" aria-label="Calendar 1"
    data-win-control="Controls.Calendar"
    data-win-options="{ year: 2012, month: 5, ondateselected: CalendarDemo.dateselected}">
</div>

You can see how we use the fully qualified name of the constructor as well as the event handler we’re assigning to ondataselected. But remember that functions referenced in markup like this have to be marked for strict processing. The constructor is automatically marked through WinJS.Class.define, but the event handler needs extra treatment: we place the function in a namespace (to make it globally visible) and use WinJS.UI.eventHandler to do the marking:

WinJS.Namespace.define("CalendarDemo", {
    dateselected: WinJS.UI.eventHandler(function (e) {
        document.getElementById("message").innerText = JSON.stringify(e.detail) + " selected";
    })
});

Again, if you forget to mark the function in this way, the control won’t be instantiated at all. (Remove the WinJS.UI.eventHandler wrapper to see this.)

To demonstrate creating a control outside of markup, the control on the right of Figure 4-9 is created as follows, within the calendar2 div:

//Since we're creating this calendar in code, we're independent of WinJS.UI.processAll.
var element = document.getElementById("calendar2");

//Since we're providing an element, this will be automatically added to the DOM
var calendar2 = new Controls.Calendar(element);

//Since this handler is not part of markup processing, it doesn't need to be marked
calendar2.ondateselected = function (e) {
    document.getElementById("message").innerText = JSON.stringify(e.detail) + " selected";
}

There you have it!

Note For a control you really intend to share with others, you’ll want to include the necessary comments that provide metadata for IntelliSense. See the “Sidebar: Helping Out IntelliSense” in Chapter 3 for more details. You’ll also want to make sure that the control fully supports considerations for accessibility and localization, as discussed in Chapter 17, “Apps for Everyone.”

Custom Controls in Blend

Blend is an excellent design tool for working with controls directly on the artboard, so you might be wondering how custom controls integrate into that story.

First, since custom controls are just elements in the DOM, Blend works with them like all other parts of the DOM. Try loading the Calendar Control Demo into Blend to see for yourself.

Next, a control can determine if it’s running inside Blend’s design mode if the Windows.ApplicationModel.DesignMode.designModeEnabled property is true. One place where this is very useful is when handling resource strings. We won’t cover resources in full until Chapter 17, but it’s important to know here that resource lookup, through Windows.ApplicationModel.Resources.ResourceLoader, doesn’t work in Blend’s design mode as it does when the app is actually running for real. To be blunt, it throws exceptions! So you can use the design-mode flag to just provide a suitable default instead of doing the lookup.

For example, one of the early partners I worked with had a method to retrieve a localized URI to their back-end services, which was failing in design mode. Using the design mode flag, then, we just had to change the code to look like this:

WinJS.Namespace.define("App.Localization", {
    getBaseUri: function () {
        if (Windows.ApplicationModel.DesignMode.designModeEnabled) {
            return "www.default-base-service.com";
        } else {
            var resources = new Windows.ApplicationModel.Resources.ResourceLoader();
            var baseUri = resources.getString("baseUrl");
            return baseUri;
        }
    }
});

Finally, it is possible to have custom controls show up in the Assets tab alongside the HTML elements and the WinJS controls. For this you’ll first need an OpenAjax Metadata XML (OAM) file that provides all the necessary information for the control, and you already have plenty of references to draw from. To find them, search for *._oam.xml files within Program Files (x86). You should find some under the Microsoft Visual Studio 11.0 folder and deep down within Microsoft SDKs where WinJS metadata lives. In both places you’ll also find plenty of examples of the 12x12 and 16x16 icons you’ll want for your control.

If you look in the controls/calendar folder of the CalendarControl example with this chapter, you’ll find calendar_oam.xml and two icons alongside the .js and .css files. The OAM file (that must have a filename ending in _oam.xml) tells Blend how to display the control in its Assets panel and what code it should insert when you drag and drop a control into an HTML file. Here are the contents of that file:

<?xml version="1.0" encoding="utf-8"?>
<!-- Use underscores or periods in the id and name, not spaces. -->
<widget version="1.0"
    spec="1.0"
    id="http://www.kraigbrockschmidt.com/scehmas/ProgrammingWin8_JS/Controls/Calendar"
    name="ProgWin8_JS.Controls.Calendar"
    xmlns="http://openajax.org/metadata">

    <author name="Kenichiro Tanaka" />

    <!-- title provides the name that appears in Blend's Assets panel
        (otherwise it uses the widget.name). -->
    <title type="text/plain"><![CDATA[Calendar Control]]></title>

    <!-- description provides the tooltip fir Assets panel. -->
      <description type="text/plain"><![CDATA[A single month calendar]]></description>

    <!-- icons (12x12 and 16x16 provide the small icon next to the control
         in the Assets panel. -->
    <icons>
        <icon src="calendar.16x16.png" width="16" height="16" />
        <icon src="calendar.12x12.png" width="12" height="12" />
    </icons>

    <!-- This element describes what gets inserted into the .html file;
         comment out anything that's not needed -->
    <requires>
        <!-- The control's code -->
        <require type="javascript" src="calendar.js" />

        <!-- The control's stylesheet -->
        <require type="css" src="calendar.css" />

        <!-- Any inline script for the document head -->
        <require type="javascript"><![CDATA[WinJS.UI.processAll();]]></require>

        <!-- Inline CSS for the style block in the document head -->
        <!-- <require type="css"><![CDATA[.control-calendar{}]]></require>-->
    </requires>

    <!-- What to insert in the body for the control; be sure this is valid HTML
         or Blend won't allow insertion -->
    <content>
        <![CDATA[
            <div class="control-calendar" data-win-control="Controls.Calendar"
                data-win-options="{ year: 2012, month: 6 }"></div>
        ]]>
    </content>
</widget>

When you add all five files into a project in Blend, you’ll see the control’s icon and title in the Assets tab (and hovering over the control shows the tooltip):

Image

If you drag and drop that control onto an HTML page, you’ll then see the different bits added in:

<!DOCTYPE html>
<html>
<head>
    <!-- ... -->
    <script src="calendar.js" type="text/javascript"></script>
    <link href="calendar.css" rel="stylesheet" type="text/css">
</head>
<body>
    <div class="control-calendar" data-win-control="Controls.Calendar"
        data-win-options="{month:6, year:2012}"></div>
</body>
</html>

But wait! What happened to the WinJS.UI.processAll() call that the XML indicated a script tag in the header? It just so happens that Blend singles out this piece of code to check if it’s already being called somewhere in the loaded script. If it is (as is typical with the project templates), Blend doesn’t repeat it. If it does include it, or if you specify other code here, Blend will insert it in a <script> tag in the header.

Also, errors in your OAM file will convince Blend that it shouldn’t insert the control at all, so you’ll need to fix those errors. When making changes, Blend won’t reload the metadata unless you reload the project or rename the OAM file (preserving the _oam.xml part). I found the latter is much easier, as Blend doesn’t care what the rest of the filename looks like. In this renaming process too, if you find that the control disappeared from the Assets panel, it means you have an error in the OAM XML structure itself, such as attribute values containing invalid characters. For this you’ll need to do some trial and error, and of course you can refer to all the OAM files already on your machine for details.

You can also make your control available to all projects in Blend. To do this, go to Program Files (x86)\Microsoft Visual Studio 11.0\Blend, create a folder called Addins if one doesn’t exist, create a subfolder therein for your control (using a reasonably unique name), and copy all your control assets there. When you restart Blend, you’ll see the control listed under Addins in the Assets tab:

Image

This would be appropriate if you create custom controls for other developers to use; your desktop installation program would simply place your assets in the Addins folder. As for using such a control, when you drag and drop the control to an HTML file, its required assets (but not the icons nor the OAM file) are copied to the project into the root folder. You can then move them around however you like, patching up the file references, of course.

Data Binding

As I mentioned in the introduction to this chapter, the subject of data binding is closely related to controls because it’s how you create relationships between properties of data objects and properties of controls (including styles). This way, controls reflect what’s happening in the data, which is often exactly what you want to accomplish in your user experience.

I want to start this discussion with a review of data binding in general, for you may be familiar with the concept to some extent, as I was, but unclear on a number of the details. At times, in fact, especially if you’re talking to someone who has been working with it for years, data binding seems to become shrouded in some kind of impenetrable mystique. I don’t at all count myself among such initiates, so I’ll try to express the concepts in prosaic terms.

The general idea of data binding is again to connect or “bind” properties of two different objects together, typically a data object (or context) and a UI object, which we can generically refer to as a source and a target. A key here is that data binding generally happens between properties, not objects.

The binding can also involve converting values from one type into another, such as converting a set of separate source properties into a single string as suitable for the target. It’s also possible to have multiple target objects bound to the same source object or one target bound to multiple source objects. This flexibility is exactly why the subject can become somewhat nebulous, because there are so many possibilities! Still, for most scenarios, we can keep the story simple.

A common data-binding scenario is shown in Figure 4-10, where we have specific properties of two UI elements, a span and an img, bound to properties of a data object. There are three bindings here: (1) the span.innerText property is bound to the source.name property; (2) the img.src property is bound to the source.photoURL property; and (3) the span.style.color property is bound to the output of a converter function that changes the source.userType property into a color.

Image

FIGURE 4-10 A common data-binding scenario between a source data object and two target UI elements, involving two direct bindings and one binding with a conversion function.

How these bindings actually behave at run time then depends on the particular direction of each binding, which can be one of the following:

One-time: the value of the source property (possibly with conversion) is copied to the target property at some point, after which there is no further relationship. This is what you automatically do when passing variables to control constructors, for instance, or simply assigning target property values using source properties. What’s useful here is to have a declarative means to make such assignments directly in element attributes, as we’ll see.

Image

One-way: the target object listens for change events on bound source properties so that it can update itself with new values. This is typically used to update a UI element in response to underlying changes in the data. Changes within the target element (like a UI control), however, are not reflected back to the data itself (but can be sent elsewhere as with form submission, which could in turn update the data through another channel).

Image

Two-way: essentially one-way binding in both directions, as the source object also listens to change events from the target object. Changes made within a UI element like a text box are thus saved back in the bound source property, just as changes to the data source property update the UI element. Obviously, there must be some means to not get stuck in an infinite loop; typically, both objects avoid firing another change event if the new value is the same as the existing one.

Image

Data Binding in WinJS

Now that we’ve seen what data binding is all about, we can see how it can be implemented within a Windows 8 app. If you like, you can create whatever scheme you want for data binding or use a third-party JavaScript library for the job: it’s just about connecting properties of source objects with properties of target objects.

If you’re anything like a number of my paternal ancestors, who seemed to wholly despise relying on anyone to do anything they could do themselves (like drilling wells, mining coal, and manufacturing engine parts), you may very well be content with engineering your own data-binding solution. But if you have a more tempered nature like I do (thanks to my mother’s side), I’m delighted when someone is thoughtful enough to create a solution for me. Thus my gratitude goes out to the WinJS team who, knowing of the common need for data binding, created the WinJS.Binding API. This supports one-time and one-way binding, both declaratively and procedurally, along with converter functions. At present, WinJS does not provide for two-way binding, but such structures aren’t difficult to set up in code.

Within the WinJS structures, multiple target elements can be bound to a single data source. WinJS.Binding, in fact, provides for what are called templates, basically collections of target elements that are together bound to the same data source. Though we don’t recommend it, it’s possible to bind a single target element to multiple sources, but this gets tricky to manage properly. A better approach in such cases is to wrap those separate sources into a single object and bind to that instead.

The best way to understand WinJS.Binding is to first see look at how we’d write our own binding code and then see the solution that WinJS offers. For these examples, we’ll use the same scenario as shown in Figure 4-10, where we have a source object bound to two separate UI elements, with one converter that changes a source property into a color.

One-Time Binding

One-time binding, as mentioned before, is essentially what you do whenever you just assign values to properties of an element. So, given this HTML:

<!-- Markup: the UI elements we'll bind to a data object -->
<section id="loginDisplay1">
    <p>You are logged in as <span id="loginName1"></span></p>
    <img id="photo1"></img>
</section>

and the following data source object:

var login1 = { name: "liam", id: "12345678",
    photoURL: "http://www.kraigbrockschmidt.com/images/Liam07.png", userType: "kid"};

we can bind as follows, also using a converter function in the process:

//"Binding" is done one property at a time, with converter functions just called directly
var name = document.getElementById("loginName1");
name.innerText = login1.name;
name.style.color = userTypeToColor1(login1.userType);
document.getElementById("photo1").src = login1.photoURL;

 function userTypeToColor1(type) {
     return type == "kid" ? "Orange" : "Black";
 }

This gives the following result, in which I shamelessly publish a picture of my kid as a baby:

Image

The code for this can be found in Test 1 of the BindingTests example for this chapter. With WinJS we can accomplish the same thing by using a declarative syntax and a processing function. In markup, we use the attribute data-win-bind to map target properties of the containing element to properties of the source object that is given to the processing function, WinJS.Binding.processAll.

The value of data-win-bind is a string of property pairs. Each pair’s syntax is <target property> : <source property> [<converter>] where the converter is optional. Each property identifier can use dot notation as needed, and property pairs are separated by a semicolon as shown in the HTML:

<section id="loginDisplay2">
    <p>You are logged in as
        <span id="loginName2"
            data-win-bind="innerText: name; style.color: userType Tests.userTypeToColor">
        </span>
    </p>
    <img id="photo2" data-win-bind="src: photoURL"/>
</section>

Note that array lookup on the source property using [ ] is not supported, though a converter could do that. On the target, if that object has a JavaScript property that you want to refer to using a hyphenated identifier, you can use the following syntax:

<span data-win-bind="this['funky-property']: source"></span>

A similar syntax is necessary for data-binding target attributes, such as the aria-* attributes for accessibility. Because these are not JavaScript properties, a special converter (or initializer as it is more property called) named WinJS.Binding.setAttribute is needed:

<label data-win-bind="this['aria-label']: title WinJS.Binding.setAttribute"></label>

Also see WinJS.Binding.setAttributeOneTime for one-time binding for attributes.

Anyway, assuming we have a data source as before:

var login2 = { name: "liamb", id: "12345678",
    photoURL: "http://www.kraigbrockschmidt.com/images/Liam07.png", userType: "kid"};

We convert the markup to actual bindings using WinJS.Binding.processAll:

//processAll scans the element's tree for data-win-bind, using given object as data context
WinJS.Binding.processAll(document.getElementById("loginDisplay2"), login2);

This code, Test2 in the example, produces the same result as Test 1. The one added bit here is that we need to define the converter function so that it’s globally accessible and marked for processing. This can be accomplished with a namespace that contains a function (again, it’s called an initializer, as we’ll discuss in the “Binding Initializers” section near the end of this chapter) created by WinJS.Binding.-converter:

//Use a namespace to export function from the current module so WinJS.Binding can find it
WinJS.Namespace.define("Tests", {
    userTypeToColor: WinJS.Binding.converter(function (type) {
        return type == "kid" ? "Orange" : "Black";
    })
});

As with control constructors defined with WinJS.Class.define, WinJS.Binding.converter automatically marks the functions it returns as safe for processing.

We could also put the data source object and applicable converters within the same namespace.30 For example (in Test 3), we could place our login data object and the userTypeToColor function in a LoginData namespace, and markup and code would look like this:

<span id="loginName3"
    data-win-bind="innerText: name; style.color: userType LoginData.userTypeToColor">
</span>

WinJS.Binding.processAll(document.getElementById("loginDisplay3"), LoginData.login);

WinJS.Namespace.define("LoginData", {
       login : {
           name: "liamb", id: "12345678",
           photoURL: "http://www.kraigbrockschmidt.com/images/Liam07.png",
           userType: "kid"
       },

       userTypeToColor: WinJS.Binding.converter(function (type) {
           return type == "kid" ? "Orange" : "Black";
       })
   });

In summary, for one-time binding WinJS.Binding simply gives you a declarative syntax to do exactly what you’d do in code, with a lot less code. Because it’s all just some custom markup and a processing function, there’s no magic here, though such useful utilities are magical in their own way! In fact, the code here is really just one-way binding without having the source fire any change events. We’ll see how to do that with WinJS.Binding.as in a moment after a couple more notes.

First, WinJS.Binding.processAll is actually an async function that returns a promise. Any completed handler given to its done method will be called when the processing is finished, if you have additional code that’s depending on that state. Second, you can call WinJS.Binding.processAll more than once on the same target element, specifying a different source object (data context) each time. This won’t replace any existing bindings, mind you—it just adds new ones, meaning that you could end up binding the same target property to more than one source, which could become a big mess. So again, a better approach is to combine those sources into a single object and bind to that, using dot notation to identify nested properties.

When targeting properties on a WinJS control and not its root (containing) element, the target property names should begin with winControl. Otherwise you’ll be binding to nonexisting properties on the root element. When using winControl, the bound property serves the same purpose as specifying a fixed value in data-win-options. For example, the markup used earlier in the “Example: WinJS.UI.Rating Control” section could use data binding for its averageRating and userRating properties as follows (assuming myData is an appropriate source):

   <div id="rating1" data-win-control="WinJS.UI.Rating"
       data-win-options="{onchange: changeRating}"
       data-win-bind="{winControl.averageRating: myData.average,
          winControl.userRating: myData.rating}">
   </div>
One-Way Binding

The goal for one-way binding is, again, to update a target property, typically in a UI control, when the bound source property changes. That is, one-way binding means to effectively repeat the one-time binding process whenever the source property changes.

In the code we saw above, if we changed login.name after calling WinJS.Binding.processAll, nothing will happen in the output controls. So how can we automatically update the output?

Generally speaking, this requires that the data source maintains a list of bindings, where each binding could describe a source property, a target property, and a converter function. The data source would also need to provide methods to manage that list, like addBinding, removeBinding, and so forth. Thirdly, whenever one of its bindable (or observable) properties changes it goes through its list of bindings and updates any affected target property accordingly.

These requirements are quite generic; you can imagine that their implementation would pretty much join the ranks of classic boilerplate code. So, of course, WinJS provides just such an implementation! In this context, sources are called observable objects, and the function WinJS.Binding.as wraps any arbitrary object with just such a structure. (It’s a no-op for nonobjects.) Conversely, WinJS.Binding.-unwrap removes that structure if there’s a need. Furthermore, WinJS.Binding.define creates a constructor for observable objects around a set of properties (described by a kind of empty object that just has property names). Such a constructor allows you to instantiate source objects dynamically, as when processing data retrieved from an online service.

So let’s see some code. Going back to the last example above (Test 3), any time before or after WinJS.Binding.processAll we can take the LoginData.login object and make it observable as follows:

var loginObservable = WinJS.Binding.as(LoginData.login)

This is actually all we need to do—with everything else the same as before, we can now change a bound property within the loginObservable object:

loginObservable.name = "liambro";

This will update the target property:

Image

Here’s how we’d then create and use a reusable class for an observable object (Test 4 in the BindingTests example). Notice the object we pass to WinJS.Binding.define contains property names, but no values (they’ll be ignored):

WinJS.Namespace.define("LoginData", {
    //...

    //LoginClass becomes a constructor for bindable objects with the specified properties
    LoginClass: WinJS.Binding.define({name: "", id: "", photoURL: "", userType: "" }),
});

With that in place, we can create an instance of that class, initializing desired properties. In this example, we’re using a different picture and leading userType uninitialized:

var login4 = new LoginData.LoginClass({ name: "liamb",
    photoURL: "http://www.kraigbrockschmidt.com/images/Liam08.jpg" });

Binding to this login object, we’d see that the username initially comes out black.

//Do the binding (initial color of name would be black)
WinJS.Binding.processAll(document.getElementById("loginDisplay"), login4);

Updating the userType property in the source (as below) would then cause an update the color of the target property, which happens through the converter automatically:

login4.userType = "kid";

Image

Implementing Two-Way Binding

To implement two-way binding, the process is straightforward:

1. Add listeners to the appropriate UI element events that relate to bound data source properties.

2. Within those handlers, update the data source properties.

The data source should be smart enough to know when the new value of the property is already the same as the target property, in which case it shouldn’t try to update the target lest you get caught in a loop. The observable object code that WinJS provides does this type of check for you.

To see an example of this, refer to the Declarative binding sample in the SDK, which listens for the change event on text boxes and updates values in its source accordingly.

Additional Binding Features

If you take a look at the WinJS.Binding reference in the documentation, you’ll see a number of other goodies in the namespace. Let me briefly outline the purpose of these. (Also refer to the Programmatic binding sample for a few demonstrations.)

If you already have a defined class (from WinJS.Class.define) and want to make it observable, use WinJS.Class.mix as follows:

var MyObservableClass = WinJS.Class.mix(MyClass, WinJS.Binding.mixin,
    WinJS.Binding.expandProperties(MyClass));

WinJS.Binding.mixin here contains a standard implementation of the binding functions that WinJS expects. WinJS.Binding.expandProperties creates an object whose properties match those in the given object (the same names), with each one wrapped in the proper structure for binding. Clearly, this type of operation is useful only when doing a mix, and it’s exactly what WinJS.Binding.define does with the oddball, no-values object we give to it.

If you remember from earlier, one of the requirements for an observable object is that is contains methods to manage a list of bindings. An implementation of such methods is contained in the WinJS.Binding.observableMixin object. Its methods are:

bind Saves a binding (property name and a function to invoke on change).

unbind Removes a binding created by bind.

Notify Goes through the bindings for a property and invokes the functions associated with it. This is where WinJS checks that the old and new values are actually different and where it also handles cases where an update for the same target is already in progress.

Building on this is yet another mixin, WinJS.Binding.dynamicObservableMixin (which is what WinJS.Binding.mixin is), which adds methods for managing source properties as well:

setProperty Updates a property value and notifies listeners if the value changed.

updateProperty Like setProperty, but returns a promise that completes when all listeners have been notified (the result in the promise is the new property value).

getProperty Retrieves a property value as an observable object itself, which makes it possible to bind within nested object structures (obj1.obj2.prop3, etc.).

addProperty Adds a new property to the object that is automatically enabled for binding.

removeProperty Removes a property altogether from the object.

Why would you want all of these? Well, there are some creative uses. You can call WinJS.-Binding.bind, for example, directly on any observable source when you want to hook up another function to a source property. This is like adding event listeners for source property changes, and you can have as many listeners as you like. This is helpful for wiring up two-way binding, and it doesn’t in any way have to be related to manipulating UI. The function just gets called on the property change. This could be used to autosync a back-end service with the source object.

The Declarative binding sample also shows calling bind with an object as the second parameter, a form that allows for binding to nested members of the source. The syntax looks like this: bind(rootObject, { property: { sub-property: function(value) { ... } } })—whatever matches the source object. With such an object in the second parameter, bind will make sure to invoke all the functions assigned to the nested properties. In such a case, the return value of bind is an object with a cancel method that will clear out this complex binding.

The notify method, for its part, is something you can call directly to trigger notifications. This is useful with additional bindings that don’t necessarily depend on the values themselves, just the fact that they changed. The major use case here is to implement computed properties—ones that change in response to another property value changing.

WinJS.Binding also has some intelligent handling of multiple changes to the same source property. After the initial binding, further change notifications are asynchronous and multiple pending changes to the same property are coalesced. So, if in our example we made several changes to the name property in quick succession:

login.name = "Kenichiro";
login.name = "Josh";
login.name = "Chris";

only one notification for the last value would be sent and that would be the value that shows up in bound targets.

Finally, here are a few more functions hanging off WinJS.Binding:

oneTime A function that just loops through the given target (destination) properties and sets them to the value of the associated source properties. This function can be used for true one-time bindings, as is necessary when binding to WinRT objects. It can also be used directly as an initializer within data-win-bind if the source is a WinRT object.

defaultBind A function that does the same as oneTime but establishes one-way binding between all the given properties. This also serves as the default initializer for all relationships in data-win-bind when specific initializer isn’t specified.

declarativeBind The actual implementation of processAll. (The two are identical.) In addition to the common parameters (the root target element and the data context), it also accepts a skipRoot parameter (if true, processing does not bind properties on the root element, only its children, which is useful for template objects) and bindingCache (an optimization for holding the results of parsing the data-win-bind expression when processing template objects).

Binding Initializers

In our earlier examples we saw some uses of converter functions that turn some bit of source data into whatever a target property expects. But the function you specify in data-win-bind is more properly called an initializer because in truth it’s only ever called once.

Say what? Aren’t converters used whenever a bound source property gets copied to the target? Well, yes, but we’re actually talking about two different functions here. Look carefully at the code structure for the userTypeToColor function we used earlier:

userTypeToColor: WinJS.Binding.converter(function (type) {
    return type == "kid" ? "Orange" : "Black";
})

The userTypeToColor function itself is an initializer. When it’s called—once and only once—its return value from WinJS.Binding.converter is the converter that will then be used for each property update. That is, the real converter function is not userTypeToColor—it’s actually a structure that wraps the anonymous function given to WinJS.Binding.converter.

Under the covers, WinJS.Binding.converter is actually using bind to set up relationships between source and target properties, and it inserts your anonymous conversion function into those relationships. Fortunately, you generally don’t have to deal with this complexity and can just provide that conversion function, as shown above.

Still, if you want a raw example, check out the Declarative binding sample again, as it shows how to create a converter for complex objects directly in code without using WinJS.Binding.converter. In this case, that function needs to be marked as safe for processing if it’s referenced in markup. Another function, WinJS.Binding.initializer, exists for that exact purpose; the return value of WinJS.Binding.converter passes through that same method before it comes back to your app.

Binding Templates and Lists

Did you think we’ve exhausted WinJS.Binding yet? Well, my friend, not quite! There are two more pieces to this rich API that lead us directly into the next chapter. (And now you know the real reason I put this entire section where I did!). The first is WinJS.Binding.List, a bindable collection data source that—not surprisingly—is very useful when working with collection controls.

WinJS.Binding.Template is also a unique kind of custom control. In usage, as you can again see in the Declarative Binding sample, you declare an element (typically a div) with data-win-control = "WinJS.Binding.Template". In that same markup, you specify the template’s contents as child elements, any of which can have data-win-bind attributes. What’s unique is that when WinJS.UI.process or processAll hits this markup, it instantiates the template and actually pulls everything but the root element out of the DOM entirely. So what good is it then?

Well, once that template exists, anyone can call its render method to create a copy of that template within some other element, using some data context to process any data-win-bind attributes therein (typically skipping the root element itself, hence that skipRoot parameter in the WinJS.Binding.declarativeBind method). Furthermore, rendering a template multiple times into the same element creates multiple siblings, each of which can have a different data source.

Ah ha! Now you can start to see how this all makes perfect sense for collection controls and collection data sources. Given a collection data source and a template, you can iterate over that source and render a copy of the template for each individual item in that source into its own element. Add a little navigation or layout within that containing element and voila! You have the beginnings of what we know as the WinJS.UI.FlipView and WinJS.UI.ListView controls, as we’ll explore in the next chapter.

What We’ve Just Learned

• The overall control model for HTML and WinJS controls, where every control consists of declarative markup, applicable CSS, and methods, properties, and events accessible through JavaScript.

• Standard HTML controls have dedicated markup; WinJS controls use data-win-control attributes, which are processed using WinJS.UI.process or WinJS.UI.processAll.

• Both types of controls can also be instantiated programmatically using new and the appropriate constructor, such as Button or WinJS.UI.Rating.

• All controls have various options that can be used to initialize them. These are given as specific attributes in HTML controls and within the data-win-options attribute for WinJS controls.

• All controls have standard styling as defined in the WinJS stylesheets: ui-light.css and ui-dark.css. Those styles can be overridden as desired, and some style classes, like win-backbutton, are used to style a standard HTML control to look like a Windows-specific control.

• Windows 8 apps have rich styling capabilities for both HTML and WinJS controls alike. For HTML controls, -ms-*-prefixed pseudo-selectors allow you to target specific pieces of those controls. For WinJS controls, specific parts are styled using win-* classes that you can override.

• Custom controls are implemented in the same way WinJS controls are, and WinJS provides standard implementations of methods like addEventListener. Custom controls can also be shown in Blend’s Assets panel either for a single project or for all projects.

• WinJS provides declarative data-binding capabilities for one-time and one-way binding, which can employ conversion functions. It even provides the capability to create an observable (one-way bindable) data source from any other object.

• WinJS also provides support for bindable collections and templates that can be repeatedly rendered for different source objects into the same containing element, which is the basis for collection controls.