Managing Layout

Excerpt from Jumping from ASP.NET to Silverlight 2

By Daniel Crenna

A fundamental task for a web developer is arranging the user interface in the most efficient, attractive, and intuitive way possible. After your application is defined and its architecture is constructed at the data and services levels, the presentation, or user interface, is the only visible aspect of your application; because of this, it becomes the most important factor in “selling” your application to others, whether it’s users in your company or the whole world. Silverlight 2’s presentation capabilities are its most impressive asset, and you’ll want to use them to their full potential. In this section, you’ll learn what you need to achieve content layouts similar to the ones you’re building today in ASP.NET.

ASP.NET layout, at its root, is accomplished through existing web standards, specifically CSS-based layouts applied with tags from directly referenced resources or bundled within ASP.NET Themes, and HTML table-based layouts.

Whether you embrace the separation of structure and style that CSS affords, as with the following example, or the simplicity and power of tables, layout in ASP.NET is no different from in other web programming models, nor is it immune to browser differences that cause applications to render differently on different browsers, a frustrating reality for users and developers alike. The following example shows a common CSS document defining the visual style for element types and attributes, and how those elements are referenced in markup to produce the desired results:

CSS code:

#body
{
position:relative;
float:left;
width:950px;
margin:0 auto;
padding:0;
}
#wrapper
{
background: transparent;
position: relative;
text-align: left;
width: 970px;
margin: 0 auto;
}
#header
{
width: 100%;
height: 20px;
position: relative;
margin: 55px 0 0;
}
#logo
{
width: 100%;
height: 120px;
margin: 0 auto;
position: relative;
background: url( 'Images/logo.png' ) no-repeat;
background-position: center;
top: 5px;
}
div, h1, h2, p, form, label, input, textarea, img, span
{
margin: 0;
padding: 0;
}
.spacer
{
clear: both;
font-size: 0;
line-height: 0;
}
html4strict Code:
<body>
<form id="form" runat="server">
<div id="header">
<br class="spacer" />
</div>
<div id="wrapper">
<div id="body" style="margin-left:10px;">
<div id="logo">
<br class="spacer" />
</div>
<center style="padding-top:8px;">
<p>
<b>
We make the best widgets!
</b>
</p>
</center>
</div>
</div>
</form>
</body> 

Silverlight 2 layout, while quite broad in scope, is accomplished through a small handful of classes. It is possible to realize most of the foundational CSS layouts with modest effort. One important distinction with Silverlight 2 is that all element visualization is vector-based rather than raster-based (the difference between images that do not lose quality however their dimensions are manipulated, and images that lose quality when they are resized larger than they are), which means that your Silverlight 2 layout and content can be scaled, rotated, and stretched to suit your application’s needs. You will often define layouts by percentage rather than true pixel count, since pixel count as it is declared in your application may not necessarily map to true pixels on the user’s browser window screen (or in the near future, mobile device). When you approach designing layouts, especially if you are building applications that are developed completely in Silverlight 2 as opposed to integrating various technologies, you should consider designing layouts that scale gracefully with browser changes, rather than hard-coding rigid pixel values that will not respond to resizing.

The three integral layout classes in Silverlight 2 are

Canvas

,

Grid

, and

StackPanel

. The object hierarchy of these three classes is such that they all share the ability to nest

UIElement

instances in their

Children

property inherited from

Panel

, as you can see in Figure 7.

Figure 7: The Silverlight control hierarchy includes three main classes for layout:

StackPanel

,

Grid

, and

Canvas

.

These three classes are responsible for realizing most scenarios you can imagine that deal with web layout.

TabPanel

is another similarly derived control that allows you to nest elements within a tab manager. Of course, you are free to develop your own layout controls, and the framework makes it easy to derive a new control based on

FrameworkElement

and override the

ArrangeOverride

and

MeasureOverride

methods accordingly, to manage child elements. Finally, there are additional controls for layout,

WrapPanel

and

DockPanel

, in the Silverlight Control Toolkit (available at www.codeplex.com/Silverlight), which you may find useful for your own layouts.

In the following example, you get a working knowledge of layout in Silverlight 2 by building a common web layout that is normally produced using CSS or tables. Figure 8 shows a few examples of common web application layouts.

Figure 8: Web-site layouts typically involve header and footer styling, a fixed sidebar, and dynamic columns of varying widths to arrange content.

Layouts like those shown in Figure 8 are ubiquitous online and consist mainly of header and footer navigation areas arranged with a sidebar and a main content window. Chances are, most of your applications are designed with a layout similar to one of these. Owing to the design’s boxed nature, you can accomplish this task using nothing but the

Grid

layout class.

The first noticeable difference between table-based layout and Silverlight 2

Grid

layout is that rows and columns are defined separately from the content in Silverlight 2, while they are combined in a traditional HTML table layout such as the following:

html4strict Code:
<table>
<tbody>
<tr>
<td class="header" colspan="2"></td>
</tr>
<tr>
<!-- content is defined within column structure -->
<td width="30%" class="sidebar"></td>
<td width="70%" class="content"></td>
</tr>
<tr>
<td class="footer" colspan="2"></td>
</tr>
</tbody>
</table>

In this familiar table-based layout, it is easy to define percentage-based widths for the sidebar and content columns. If this table is part of a larger design, those columns will adjust based on the surrounding elements in order to fill the appropriate amount of space. In addition, any content presented in the table must be declared within the structure. That is, column content is declared within the column tag block, and nowhere else.

In the following code, you will declare a similar layout in Silverlight 2 by using the

Grid

control:

ManagingLayout.xaml

xml Code:

<Grid x:Name="layoutOne"
Background="White"
Width="200"
Height="200"
ShowGridLines="true">
 
<!-- One row each for the header, content, and footer-->
<Grid.RowDefinitions>
<RowDefinition Height="25"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="25"></RowDefinition>
</Grid.RowDefinitions>
 
<!-- A total of two columns that make up the sidebar and content -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
 
<Rectangle Fill="#7f0000" Grid.Row="0" Grid.ColumnSpan="2"/>
<Rectangle Fill="#333333" Grid.Row="1" />
<Rectangle Fill="#7f0000" Grid.Row="2" Grid.ColumnSpan="2"/>
</Grid>

Examining this Silverlight 2 grid layout, you see that the row and column definitions occur before any content is declared. The content, in this case, simple

Rectangle

shapes with a filled-in color, is specified below the definitions, and the content location in relation to the grid’s layout is provided through the

Grid

attached property (you learned about attached properties in the “XAML versus ASP.NET markup” section). Following the code, you can see that the first burgundy (

#7f000

) rectangle occupies the first grid row and spans both column definitions. The silver (

#333333

) sidebar rectangle tag occupies the second row but only covers the first column, leaving the content column alone. The footer fills out the rest of the final row.

On closer inspection, this

Grid

layout is incomplete. On one hand, you declare a

Grid

with a specific 200 ´ 200 pixel area, which won’t cover the whole screen, and on the other, you hard-code the header, footer, and sidebar widths as fixed pixels. You need to re-design this layout so that your widths are percentage-based, and the grid itself can occupy the entire visible application window.

ManagingLayout.xaml

xml Code:

<Grid x:Name="layoutOne"
Background="White"
 
Width="Auto"
Height="Auto"
ShowGridLines="true">
 
<!-- One row each for the header, content, and footer-->
<Grid.RowDefinitions>
 
<RowDefinition Height=".25*"></RowDefinition>
<RowDefinition Height="1*"></RowDefinition>
<RowDefinition Height=".25*"></RowDefinition> </Grid.RowDefinitions>
 
<!-- A total of two columns that make up the sidebar and content -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".30*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
 
<Rectangle Fill="#7f0000" Grid.Row="0" Grid.ColumnSpan="2"/>
<Rectangle Fill="#333333" Grid.Row="1" />
<Rectangle Fill="#7f0000" Grid.Row="2" Grid.ColumnSpan="2"/>
</Grid>

So what changed to make your layout percentage-based and expanded to fit the entire application window? First, you replaced the grid’s specific pixel width and height with

Auto

values. These values allow you to rely on the parent element when determining the size of the current element. This means that the

Grid

’s parent

UserControl

and its parent, all the way up to the

UserControl

responsible for containing your application, must all use

Auto

to ensure that the size of your application is bound only to the

Silverlight

control that exists in the host ASP.NET web application that’s serving your application’s XAP file. In the case of a new Silverlight 2 application, this is always the entire browser page, unless you’ve configured your landing page differently.

The next change is a little trickier. In Silverlight 2, percentage-based layout is specified relative to any other percentage-based value provided in the definition block, and is post-fixed by the “

*

” value as if it were a “%” sign with a subtle variation. In the revised markup, what you’re describing is that the height of the header row is, relative to the content row, a quarter the size, since 0.25 is 25 percent of 1. If it’s easier for you to adjust to larger numbers, you can replace the values above with 25, 100, and 25, respectively, and produce the same result: the header and footer rows are always maintained at 25 percent of the content row.

Now that you have a defined sidebar and content area in your layout, you can use the

StackPanel

to add buttons to the sidebar. When you add a

UIElement

to a

StackPanel

, that element will display in the next available space to the previously added element, depending on the panel’s

Orientation

property and any boundaries specified in your design. This is convenient for lining up similar controls together, such as buttons or navigation markers. This layout feature is similar to listing HTML elements in an unordered list or adding ASP.NET

Button

controls dynamically to an ASP.NET

Panel

control.

ManagingLayout.xaml

xml Code:

<Grid x:Name="layoutOne"
Background="White"
Width="Auto"
Height="Auto"
ShowGridLines="true">
 
<!-- One row each for the header, content, and footer-->
<Grid.RowDefinitions>
<RowDefinition Height="25*"></RowDefinition>
<RowDefinition Height="100*"></RowDefinition>
<RowDefinition Height="25*"></RowDefinition>
</Grid.RowDefinitions>
 
<!-- A total of two columns that make up the sidebar and content -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width=".3*"></ColumnDefinition>
<ColumnDefinition Width="1*"></ColumnDefinition>
</Grid.ColumnDefinitions>
 
<Rectangle Fill="#7f0000" Grid.Row="0" Grid.ColumnSpan="2"/>
<Rectangle Fill="#333333" Grid.Row="1" />
<StackPanel Orientation="Vertical" Grid.Row="1">
<Button Content="Option 1"></Button>
<Button Content="Option 2"></Button>
<Button Content="Option 3"></Button>
<Button Content="Option 4"></Button>
<Button Content="Option 5"></Button>
</StackPanel>
<Rectangle Fill="#7f0000" Grid.Row="2" Grid.ColumnSpan="2"/>
</Grid>

It’s worth noting that, even though both the

StackPanel

with the sidebar buttons and the filled color

Rectangle

are set up to occupy the first column in the second row in the grid, the content of both elements is respected. Keep in mind that content that is applied to a grid row area is applied in an overlapping fashion, meaning that the

Rectangle

with its fill style is first applied to the row, followed by the

StackPanel

; if you reversed the order, the

Rectangle

would apply on top of the

StackPanel

, hiding its contents.

The

Canvas

control, shown in the following code, is useful for building layouts that rely on ordering by depth, as well as arranging content that moves along the left and top edges of a layout. These effects are achieved through the

ZIndex

,

Top

, and

Left

properties exposed by the control. CSS-based web layouts use

z-index

attributes when stacking elements like

DIV

tags that require that specific elements appear on top of, or behind, other elements, which is not always the order of an element’s appearance in HTML. The higher the

z-index

value, the closer the relative distance to the top of the visual tree an element will appear.

ManagingLayout.xaml

xml Code:

<Canvas Grid.Row="1"
Grid.Column="1"
Width="Auto"
Height="Auto">
 
<!-- Some cascading rectangles -->
<Rectangle Fill="#ffefa4"
Width="20"
Height="20"
Canvas.Left="30"
Canvas.Top="30"></Rectangle>
 
<!-- This one rises to the top -->
<Rectangle Fill="#bf9e68"
Width="20"
Height="20"
Canvas.ZIndex="2"
Canvas.Left="40"
Canvas.Top="40"></Rectangle>
 
<Rectangle Fill="#7171a4"
Width="20"
Height="20"
Canvas.Left="50"
Canvas.Top="50"></Rectangle>
</Canvas>

You now have the ability to arrange a Silverlight 2 web application’s layout into rows and columns of content, stack repeating elements together, and handle positional offsets horizontally, vertically, and in depth. These fundamental concepts should help you effectively arrange a Silverlight 2 application to match a design document.

Tags:

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *