(X) Hide this
    • Login
    • Join
      • Generate New Image
        By clicking 'Register' you accept the terms of use .

Windows Store apps with XAML and HTML: Layout elements into the page.

(1 votes)
Andrea Boschin
Andrea Boschin
Joined Nov 17, 2009
Articles:   91
Comments:   9
More Articles
0 comments   /   posted on Apr 08, 2013
Categories:   Windows 8


If you have a minimal experience in building web sites with HTML and CSS, you know for sure that creating a decent layout is someway hard. This comes from the way the browser renders the page, privileging the horizontal dimension on the vertical (that is potentially unlimited in height) but also from the many different flavours of browsers that gives a slightly different interpretation to the moltitude of specifications. On the other side, XAML programmers have a very strong layout system that makes thing really easy, thanks to a series of panels that acts with different behaviors in a consistent and predictable way. The real point here is that usually people is confused about the usage of these two tools. Building an application layout with HTML into the browser is something crazy as it is doing a website layout with XAML. They have its own specific scope and they act at the best when properly used for the purpose they have build for.

This to explain my surprise when I've known that I should build Windows Store apps, with plain HTML. The layout expected for this kind of application were far away from the concept I had, of what HTML can do. And it was only when I put my nose into the problem I discovered that the HTML in Windows Store Apps has some more bullets then a normal browser rendering engine.

Put elements into the page

When you have to choose a layout for your application there is two ways to follow that depend from the behavior you need. Typically you can use a fixed layout for dashboards or games and a scrollable layout for common Store apps that rely on the Modern UI interface. Usually these have an horizontal scrolling the goes out of the size of the screen maximizing the available space and are mostly targeted to publishing related apps like readers, and content browsers.

In both the cases you have to organize elements on the page to fill the space and adapt them according to the page size. Given the multiple form factors that are available for Windows 8 devices it is important have a strong layout system that can support all the needs. Using XAML there are three fundamental layout system: Canvas, StackPanel and the Grid. These are perfectly nestable one inside the other to compose awesome layouts that resolve all the needs you can face.

To resume for the HTML people the Canvas is an absolute positioning system, where the panel gives an origin to the elements and you position using a cartesian coordinate system. Here is an example:

   1: <Canvas>
   2:     <Rectangle Canvas.Left="200" Canvas.Top="200" Fill="Red" Width="100" Height="100" />
   3:     <Ellipse Canvas.Left="300" Canvas.Top="400" Fill="Yellow" Width="100" Height="100" />
   4:     <Rectangle Canvas.Left="600" Canvas.Top="300" Fill="Red" Width="30" Height="400" />
   5: </Canvas>

As you can see the three elements into the canvas are positioned using the Canvas.Left and Canvas.Top properties that are the X and Y coordinates. This kind of layout is the most simple and the less useful, because absolutely positioned items do not automatically adapt to the layout changes, so on different devices, they must be repositioned to avoid unwanted trimmings. In HTML the absolutely positioned elements can be achieved using CSS as follow:

   1: <div>
   2:     <div style="position: fixed; left: 200px; top: 200px; width: 100px; height: 100px; background-color: red;"></div>
   3:     <svg style="position: fixed; left: 300px; top: 400px; width: 100px; height: 100px; background-color: transparent;">
   4:         <ellipse cx="50" cy="50" rx="50" ry="50" style="fill: yellow; stroke-width: 0" />
   5:     </svg>
   6:     <div style="position: fixed; left: 600px; top: 300px; width: 30px; height: 400px; background-color: red;"></div>
   7: </div>

Please take note that in this example and in the following the styles are set into the html but the best practice is to put the styles in a separate file and then apply them to html elements using classes and ids. The above example use the following CSS attributes:

  • position: the "fixed" value asks for an element positioned using an absolute coordinate system
  • left, top: these are the X and Y coordinate of the element into its container
  • width, height: the x and y size of the element

Since the HTML is not a vector graphics language you have to rely on a "svg" element ("scalable vector graphics") and draw your ellipse inside of it. Probably it should be easy to directly draw all the elements inside the svg tag but it is not always applicable.

A most advanced layout system, that is also the natural behavior for HTML elements is the Stacked layout. Using XAML you can take advantage of a StackPanel to position elements stacked both for horizontal and vertical direction. Here is an example:

   2: <StackPanel Orientation="Vertical">
   3:     <Rectangle Fill="Orange" Stroke="Black" StrokeThickness="1" Height="30" />
   4:     <Rectangle Fill="Orange" Stroke="Black" StrokeThickness="1" Height="30" />
   5: </StackPanel>
   7: <StackPanel Orientation="Horizontal">
   8:     <Rectangle Fill="Orange" Stroke="Black" StrokeThickness="1" Width="30" />
   9:     <Rectangle Fill="Orange" Stroke="Black" StrokeThickness="1" Width="30" />
  10: </StackPanel>

Also if the vertical stacked is the default layout for HTML elements, it is really hard to create a layout similar to the XAML I proposed, without additional styles. In Windows Store apps they added the specification for flex-box CSS to allow a very effective stack layout. The -ms-flexbox value for the display attribute helps to better organize the layout in a very similar way to the XAML stack panel. Here is an example:

   1: <div style="display:-ms-flexbox;-ms-flex-direction: column;">
   2:     <div style="height: 30px; background-color: orange; border: solid black 1px;"></div>
   3:     <div style="height: 30px; background-color: orange; border: solid black 1px;"></div>
   4:     <div style="height: 30px; background-color: orange; border: solid black 1px;"></div>
   5: </div>
   7: <div style="display:-ms-flexbox;-ms-flex-direction: row;">
   8:     <div style="width: 30px; background-color: orange; border: solid black 1px;"></div>
   9:     <div style="width: 30px; background-color: orange; border: solid black 1px;"></div>
  10:     <div style="width: 30px; background-color: orange; border: solid black 1px;"></div>
  11: </div>

The flex-box CSS is very "flexible" and has a number of additional attributes that enable fine tuning of element positioning. Thanks to the flexbox it is possible to emulate also the WrapPanel, stacking elements horizontally or vertically and making them to flow when the available space ends. To get in touch with all these attributes have a look at this page where you can configure the css for a flexbox: http://ie.microsoft.com/testdrive/Graphics/hands-on-css3/hands-on_flex.htm.

The last and most advanced way of doing layout in XAML is the Grid panel. It is made to slice the space in rows and columns and then it accepts elements that hooks up to the resulting cells and span horizontally and vertically. the beautiful is that you can size columns and rows in different ways, with percentage values, fixed pixels and automatically calculates on content size. This feature let you better organize elements as they resize easily when the  container is resized. As for other cases here a simple example:

   1: <Grid>
   2:     <Grid.RowDefinitions>
   3:         <RowDefinition Height="100" />
   4:         <RowDefinition Height="*" />
   5:         <RowDefinition Height="100" />
   6:     </Grid.RowDefinitions>
   7:     <Grid.ColumnDefinitions>
   8:         <ColumnDefinition Width="100" />
   9:         <ColumnDefinition Width="*" />
  10:         <ColumnDefinition Width="100" />
  11:     </Grid.ColumnDefinitions>
  13:     <Rectangle Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="3" Grid.RowSpan="1" Fill="Blue" />
  14:     <Rectangle Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="1" Grid.RowSpan="1" Fill="Gray" />
  15:     <Rectangle Grid.Column="1" Grid.Row="1" Grid.ColumnSpan="1" Grid.RowSpan="1" Fill="Green" />
  16:     <Rectangle Grid.Column="2" Grid.Row="1" Grid.ColumnSpan="1" Grid.RowSpan="1" Fill="Gray" />
  17:     <Rectangle Grid.Column="0" Grid.Row="2" Grid.ColumnSpan="3" Grid.RowSpan="1" Fill="Blue" />
  19: </Grid>

The RowDefinitions property and the ColumnDefinitions property are responsible of slicing the space available, then the Row, Column, RowSpan and ColumnSpan let you positioning the elements. In plain HTML this layout is completely unavailable. Lot of times I fight with absolute positionig to achieve a similar layout but it is always an hard battle that hurts. In the rendering engine of HTML apps for the Windows Store they implemented a grid layout that is very close to the XAML, but it is applied using CSS:

   1: <div style="display:-ms-grid;-ms-grid-columns:100px 1fr 100px;-ms-grid-rows:100px 1fr 100px;">
   2:     <div style="background-color: blue; -ms-grid-column:1; -ms-grid-row: 1; -ms-grid-column-span: 3; -ms-grid-row-span: 1; z-index: 1; opacity: 1;"></div>
   3:     <div style="background-color: gray; -ms-grid-column:1; -ms-grid-row: 2; -ms-grid-column-span: 1; -ms-grid-row-span: 1; z-index: 1; opacity: 1;"></div>
   4:     <div style="background-color: green; -ms-grid-column:2; -ms-grid-row: 2; -ms-grid-column-span: 1; -ms-grid-row-span: 1; z-index: 1; opacity: 1;"></div>
   5:     <div style="background-color: gray; -ms-grid-column:3; -ms-grid-row: 2; -ms-grid-column-span: 1; -ms-grid-row-span: 1; z-index: 1; opacity: 1;"></div>
   6:     <div style="background-color: blue; -ms-grid-column: 1; -ms-grid-row: 3; -ms-grid-column-span: 3; -ms-grid-row-span: 1; z-index: 1; opacity: 1;"></div>
   7: </div>

Also if the grid system is zero-based in XAML and one-based in HTML, the values acts exatly the same in creating the Grid. The "1fr" syntax means 1-fraction that is more or less like saying a percentage with XAML but it is calculated on the basis of all the fractions defined for the same row or column. So, "1fr,1fr,1fr" should be intended as "33%,33%,33%" and instead "1fr,2fr,1fr" is "25%,50%,25%". Again to experiment this layout use the following page and then cut&paste the resulting style: http://ie.microsoft.com/testdrive/Graphics/hands-on-css3/hands-on_grid.htm

Handling ViewStates changes

The ViewState in Windows Store apps directly impacts how the layout is done because it determines the current size of the available space. In the transition between FullScreenPortait, FullScreenLandscape, Snapped and Filled the changes in sizes must be handled to specify visible elements for each state. These changes are raised as events in C# base class and they are handled usually using a series of VisualStateManager states. Thanks to this choice they can be designed easily in Blend that directly supports the states. When you create a project, VisualStudio adds a base page class called LayoutAwarePage. Inside of this class you can see how they handle the ViewState changes mapping them to states that have the same name. Then you define a number of animations, one for each element that have to change when the ViewState changes, and the LayoutAwarePage does the rest.

   1: <VisualStateManager.VisualStateGroups>
   2:     <VisualStateGroup x:Name="ViewState">
   3:         <VisualState x:Name="FullScreenLandscape" />
   4:         <VisualState x:Name="Filled" />
   5:         <VisualState x:Name="Snapped">
   6:             <Storyboard>
   7:                 <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="fullList">
   8:                     <DiscreteObjectKeyFrame KeyTime="0">
   9:                         <DiscreteObjectKeyFrame.Value>
  10:                             <Visibility>Collapsed</Visibility>
  11:                         </DiscreteObjectKeyFrame.Value>
  12:                     </DiscreteObjectKeyFrame>
  13:                 </ObjectAnimationUsingKeyFrames>
  14:                 <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="snappedList">
  15:                     <DiscreteObjectKeyFrame KeyTime="0">
  16:                         <DiscreteObjectKeyFrame.Value>
  17:                             <Visibility>Visible</Visibility>
  18:                         </DiscreteObjectKeyFrame.Value>
  19:                     </DiscreteObjectKeyFrame>
  20:                 </ObjectAnimationUsingKeyFrames>
  21:                 <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="fullFiller">
  22:                     <DiscreteObjectKeyFrame KeyTime="0">
  23:                         <DiscreteObjectKeyFrame.Value>
  24:                             <Visibility>Collapsed</Visibility>
  25:                         </DiscreteObjectKeyFrame.Value>
  26:                     </DiscreteObjectKeyFrame>
  27:                 </ObjectAnimationUsingKeyFrames>
  28:             </Storyboard>
  29:         </VisualState>
  30:         <VisualState x:Name="FullScreenPortrait" />
  31:     </VisualStateGroup>
  32: </VisualStateManager.VisualStateGroups>
Honestly speaking I do not advise to use the LayoutAwarePage that is generated by the Visual Studio 2012 template. It has some flaws that you better handle using your own implementation but the way it works is for sure a good track to create your own.

In HTML the VisualStateManager does not exists. Instead the CSS comes to the rescue with the media-queries that are something very close to the VisualStateManager. Media queries apply to particular states of the page and usually are for targeting html to different devices into the browser. Into the Windows Runtime they have been extended to cover also the ViewStates with some specific states.

   1: @media screen and (-ms-view-state: snapped) {
   2:     .groupeditemspage section[role=main] {
   3:         -ms-grid-row: 2;
   4:         -ms-grid-row-span: 1;
   5:     }
   7:     .groupeditemspage .groupeditemslist .win-vertical.win-viewport .win-surface {
   8:         margin-bottom: 30px;
   9:         margin-top: 0;
  10:     }
  12:     .groupeditemspage .groupeditemslist .win-container {
  13:         margin-bottom: 15px;
  14:         margin-left: 13px;
  15:         margin-right: 35px;
  16:         padding: 7px;
  17:     }
  19:     .groupeditemspage .groupeditemslist .item {
  20:         height: 75px;
  21:         width: 260px;
  22:     }
  24:         .groupeditemspage .groupeditemslist .item .item-overlay {
  25:             display: -ms-grid;
  26:             -ms-grid-columns: 2;
  27:             -ms-grid-rows: 1;
  28:             background: transparent;
  29:             padding: 0;
  30:         }
  32:             .groupeditemspage .groupeditemslist .item .item-overlay .item-title {
  33:                 -ms-grid-column: 1;
  34:             }
  36:             .groupeditemspage .groupeditemslist .item .item-overlay .item-subtitle {
  37:                 -ms-grid-column: 2;
  38:             }
  39: }

The example code I proposed shows the use of a media query when "-ms-view-state" equals "snapped". In this query the css apply some different sizes in margins and positioning into the rows and columns. When I see this the very first time I was really impressed and I'm currently thinking that probably this implementation has a number of advantages on the XAML ViewStateManager. I believe that everything you can do with media queries is also available with VisualStateManager but it is implicitly supported by the runtime that does not requires a special page to generate media queries states. Also, applying this to css directly simply leave the page much more clean and simple.

Moving forward

After getting in touch with layout, now you are ready to start building your pages and putting togheter elements and controls to create your implementation. It is time to start enter the range of available controls, that are often specular between html and xaml with a number of exception. This will be the argument of the next number of the series.



No comments

Add Comment

Login to comment:
  *      *       

From this series