In Windows 8 and WinJS 1.0 it was exceedingly difficult (though not impossible) to create a custom layout object for the WinJS ListView control. As such it was one area of WinJS that I never investigated!

What made it difficult was that the ListView worked entirely on absolute CSS positioning, which meant that the location of every item had to be individually calculated within the layout object’s code. This also caused various performance issues as well.

For WinJS 2.0 on Windows 8.1, the WinJS team rewrote the layout engine of the ListView to leverage relative positioning such that it could let the app host’s layout engine do most of the work. This both improved performance and made it orders of magnitude more easy to write a custom layout. In fact, the simplest layout object hardly needs to do anything at all, because the default behavior (via flexbox with block elements) produces a simple vertical layout just like you get when throwing a bunch of div’s into an HTML page.

From there you can start to build out other behaviors you want:

  • Non-vertical layouts
  • Virtualization support
  • Keyboard support
  • Drag and drop general visual indicators
  • Drag and drop reordering and positional indicators
  • Animations

To explore all the details, I have 17 pages in Appendix B, “WinJS Extras” in my free ebook’s second edition (preview), which includes a minimal vertical layout, a minimal horizontal layout, two dimensional layouts, and non-linear layouts. For the latter I borrowed some code from Mike Mastrangelo of the WinJS team that was used in a short demo at //build 2013. The appendix also includes a short video demonstration of this.

B-3 (circle layout)


Question: Is there an easy way to detect when the Charms bar is opened (such as to pause a game at such times)?

Answer: Yes, you can use the HTML blur event for this purpose, as opening the Charms pane will take focus away from the app (and closing it will cause a focus event). What’s important here is that you listen to the window object’s blur event, rather than any other specific element. For example:

window.addEventListener(“blur”, handleEvent, false);

handleEvent gets called when you activate charms via touch (in the simulator at least) and keyboard. The one case that it doesn’t seem to work is when you pull the charms out with the mouse in the lower right. For this, listen for the body element’s mouseleave event and handle it the same way as blur (even using the same handler).

Note that blur is not fired when the app bar appears, as that’s still keeping focus on the same app window (it’s app UI, not system UI). For this you can use the app bar’s beforeshow/aftershowevent, or you can use the blur event on the body element.
Question: I want to automatically close the charms pane from within one of my settings flyouts. How can I do this?

Answer: It’s very simple, just call window.focus() to set the focus back to the app, which automatically dismisses the charms bar. Navigating to a page with WinJS.Navigation.navigate has the same effect (as it sets the focus in the process).


As a short follow-up to the previous series of posts, I wanted to share a bit on detecting where a view is on the screen. That is, a view can be placed anywhere on the screen, which could be on either edge or in the middle (which is demonstrated in the Getting Around tutorial video.) For any given view, the ApplicationView object for which you obtain with Windows.UI.ViewManagement.ApplicationView.getForCurrentView(), its adjacentToLeftDisplayEdge and adjacentToRightDisplayEdge properties tell you whether the view is placed along a screen edge. If, also, the view is full screen, the isFullScreen property will be true as will both adjacent* properties.

It follows, then, that !isFullScreen && !adjacentToLeftDisplayEdge && !adjacentToRightDisplayEdge means that a view is split and is centrally placed.

 

 


To determine whether a device supports orientation changes–that is landscape, portrait, landscape-flipped, and portrait-flipped orientations–the simplest way is to just check whether an orientation sensor exists.

Call Windows.Devices.Sensors.SimpleOrientationSensor.getDefault() and if the return value is non-null, there is an orientation sensor.

For details on the APIs, see getDefault, the SimpleOrientationSensor sample, and Quickstart: Determining device orientation.


Typically, when a user rotates an accelerometer-equipped device, Windows will rotate the display to the nearest quadrant (landscape, portrait, landscape-flipped, and portrait-flipped) and apps will receive a resize event in which they can adjust their layout.

Some apps, however, prefer to keep their layout as-is, regardless of device rotation. A full screen video player, for example, wants to remain in landscape irrespective of the device orientation, allowing you to watch videos while laying sideways on a couch with a tablet propped up on a chair!

Locking the orientation can be done in two places. First, you can specify the orientations the app supports in the app manifest under Supported Rotations on the Application UI tab:

sidebar (preferred orientations)

By default, all these options are unchecked which means the app will be resized (and thus redrawn) when the device orientation changes (and checking all of them means the same thing). When you check a subset of the options, the following effects apply:

  • If the device is not in a supported rotation when the app is launched, the app is launched in the nearest supported rotation. For example, if you check Portrait and Landscape-flipped (I have no idea why you’d choose that combination!), and the device is in Landscape mode, the app will launch into Portrait.
  • When the app is in the foreground, rotating the device to a non-supported orientation has no effect on the app.
  • When the user switches away from the app, the device orientation is restored unless the new foreground app also has preferences. Of course, it’s likely that the user will have rotated the device to match the app’s preference, in which case that’s the new device orientation.
  • When the user switches back to the app, it will switch to the nearest supported rotation.
  • In all cases, when the app’s preference is in effect, system edge gestures work relative to that orientation, that is, the left and right edges relative to the app’s orientation.

You can achieve the same effects at runtime—changing preferences dynamically and overriding the manifest—by setting the autoRotationPreferences property of the Windows.Graphics.Display.DisplayInformation object (this is the one you use in Windows 8.1; in Windows 8, use the DisplayProperties object instead). The preference values come from the DisplayOrientations enumeration, and can be combined with the bitwise OR (|) operator. For example, here are the bits of code (JavaScript) to set a Portrait preference and the combination of Portrait and Landscape-flipped (Windows 8.1):

var wgd = Windows.Graphics.Display;
wgd.DisplayInformation.autoRotationPreferences = wgd.DisplayOrientations.portrait;
wgd.DisplayInformation.autoRotationPreferences = wgd.DisplayOrientations.portrait | wgd.DisplayOrientations.landscapeFlipped;

Note that orientation preferences set in the manifest and through the autoRotationPreferences property do not work with non-accelerometer hardware, such as desktop monitors and also the Visual Studio simulator. The rotations that the simulator performs happen in a different way than those induced by a real accelerometer. To really test these preferences, in other words, you’ll need a real device equipped with that sensor.

To play around with these settings, refer to the Device auto rotation preferences sample. Its different scenarios set one of the orientation preferences so you can see the effect when the device is rotated; scenario 1 for its part clears all preferences and restores the usual behavior for apps. You can also change rotation settings in the manifest to see their effects, but those are again overridden as soon as you change the preferences through any of the scenarios.


Apps need to be prepared for a variety of display sizes. For one, a user can switch view states at any time, putting the app into snapped view, filled view, and fullscreen landscape. The user can also rotate a device to switch to portrait automatically (on devices with appropriate sensors). These are the basics for a tablet device like a Surface.

But also remember that as WIndows 8 runs on many different kinds of devices, there are many other ways that display properties can be changed.

For example, think of everything that can happen through the Display settings in Control Panel. The user can rotate a display directly (as when using a desktop monitor that swivels), which will change a view state to fullscreen portrait as well. The user can change display resolution, which clearly changes the size of fullscreen and filled views, as well as the vertical dimension of a snapped view.

On multi-monitor systems, the user can also change which monitor is assigned to run Windows Store apps, which potentially has the same effect as changing display resolution if those monitors are different.

A user could also plug an external display into a device: monitors, projectors, and so forth. Depending on how the user configures that display–duplicating the main device, extending the display, or switching exclusively to the external display–the screen resolution can change as well as the pixel density. For example, a Surface Pro has a 1920×1080 screen that puts the 140% scaling into effect because it’s only a 10.6″ screen. But plug it into a monitor with the same resolution and the scaling can revert to 100%. (This means that the app will see an effective resolution change from approxmately 1366×768 to 1920×1080.)

The bottom line is that apps really need to watch for the relevant resize event (such as window.resize in JavaScript) and update their layout both for window/screen dimensions and pixel density–and don’t overlook the non-obvious cases when running some tests. It’s good to try all the things described here.

Beyond this, two other software features could be cause for resizing the app: app bars and the soft keyboard. By default, these appear as overlays on the app’s canvas, and with the keyboard Windows will also pan the app up automatically to make room. If you want more sophsiticated behavior, though, you can handle the events when these become visible and update your layout more precisely.


Developers sometimes ask about handling devices with different screen sizes, and whether that was something you’d could do with media queries in addition to the media queries for the different view states (snapped, filled, fullscreen-landscape, and fullscreen-portrait).

The answer is really to use adaptive (aka responsive) layout techniques with CSS so that you don’t really worry about screen size—you’re typically only writing media queries for the view states, since the relative positioning of items in the page layout can change quite a bit between them. In those view state media queries, you might be changing the size of an element that contains a grid layout div, or that of a ListView, or some other control, where that size change will trigger a resize event that a control like ListView picks up to refresh its layout. Apps also use the same event to change the layout of a ListView according to view state, such as switching between GridLayout (2D) and ListLayout (1D, vertical).

It’s worth noting that inside media queries there are the vh and vw units (viewport height and viewport width) that can be used like px, em, etc. That is, saying height: 6.5vh in CSS will give you 6.5% of the height of the app window. You can certainly accomplish the same thing with a CSS grid, where you know that certain fractional rows/columns will essentially come out the same thing. For example, if you have a grid that’s styled to 100% width and height, and use –ms-grid-columns: 1fr 1fr 1fr 1fr; that’d be the same as using –ms-grid-columns: 25vw 25vw 25vw 25vw. Or –ms-grid-columns: 25% 25% 25% 25%. But if that element was only 50% width, then the 1fr and 25% values will scale, but the 25vw would not, unless the display width itself changed.

I mention those because if you have layout that’s not strictly proportional and does depend on screen dimensions, you can use vh and vw like this, or you can standard media queries against width and height, combined with the view states, as needed. For example, say in snap view you’ll have your base layout for a 768 vertical dimension, but if you’re on something greater than, say, 1200, you might want to include another piece of information in the header or such. In that case, the extra element would be present in the HTML, then you’d have a media query like this:

@media screenand(-ms-view-state: snapped) and (max-height: “1199px”) {
/**/
}

wherein you might set display: none for that extra element.

Within JavaScript you can also obtain window and element dimensions as you need them if you’re working with layout programmatically (such as cases where you need to do some extra computation).

So it really depends on what you need to do, layout-wise, but the platform can provide all the information you need both declaratively and programmatically. You can also use Media Query Listeners (another W3C standard) to get events for view state changes.