Chapter 2. Laying out Our User Interface

We will continue our journey to become a Silverlight guru by covering the different aspects of laying out a user interface in Silverlight. In this chapter we will get some hands-on experience of laying out, displaying, and creating different controls. We have a lot to cover, so let's get going and write some code!

In this chapter we will cover the following topics:

  • Arranging content with panels
  • Using core and content controls
  • Creating user controls
  • The navigation framework
  • Displaying a collection of items
  • Playing media files
  • Test your knowledge

Arranging content with panels

Imagine the following scenario:

You are responsible for building your company's new BI dashboard. You get the requirements from your superior, and you notice one of the requirements is that your application must support all of the different screen resolutions in the office. This is exactly the point of knowing the different panels that Silverlight offers and how they come into play. Silverlight, being a rich UI framework, offers six different kinds of layout panels for different causes, and as nothing beats seeing things for yourself, we will now create our first Silverlight application to see how the panels differentiate from one another.

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

Creating your first Silverlight application

To begin, you will need to complete the following steps:

  1. Open Visual Studio 2010, click on New Project..., select Silverlight from the Installed Templates list on the left-hand side of the window, and click on Silverlight Application. Name the new application as Chapter2-Layouts. Your screen should look similar to the following screenshot:
    Creating your first Silverlight application
  2. To actually create the project, click on the OK button. You'll get a pop-up window asking you if you would like to host your Silverlight application within an ASP.NET website. Hosting your application in such a website makes it easier for us to debug and display the application, so don't change anything in this window and just click on OK.
  3. We have just created our first Silverlight application! Your visual studio should look similar to the following screenshot:
    Creating your first Silverlight application

Right now, our new application might look like a blank white box, but under the hood you might notice the first layout panel we are going to discuss—Grid.

Grid

The Grid control can be considered as Silverlight's equivalent to the good old HTML table element. Just like the HTML table, the Grid control allows you to arrange controls in rows and columns, span a control across multiple rows or columns, and define different heights and widths for each row or column. Grid is the control you're most likely to use the most. Not only is it the default root element control for the UserControl and page templates, but it is also the best control to use when you want your content to extend/shrink according to the space available for it. In order to define rows and columns in a grid, we use the grid's Element properties—RowDefinitions and ColumnDefinitions—respectively.

These properties act as collections for the RowDefinition and ColumnDefinition elements, which as you might have guessed, define a single row or column. Let's take this theory to practice, and add two rows and two columns to our LayoutRoot grid. Add the following code snippet between the starting and closing tags for your LayoutRoot:

<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>

In order to see the boundaries of each cell, add the inline property—ShowGridLines—to the Grid element, and give it the value of True, so your Grid element should look as follows:

<Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True">

Press F5 to build and launch the application. You should now have a grid divided into two columns and two rows, as shown in the following screenshot:

Grid

As we didn't specify fixed values for the grid's dimensions, the grid will resize itself according to the space available to it. If you resize the window where the grid is rendered, you will see that the grid resizes itself according to the new window's size.

Setting the dimensions of a grid or almost any other Silverlight control, is done by specifying a fixed number of pixels to the Width and Height properties; setting these properties for a RowDefinition or ColumnDefinition element is quite different.

Unlike most Silverlight controls, the Width and Height properties of ColumnDefinition and RowDefinition are represented as the GridLength values. GridLength allows you to select between three different ways to allocate the available space, and as the default selection is star sizing we will start with it.

Star sizing

Star sizing is used when you wish to distribute the available space of the grid equally between its rows or columns. Star sizing is calculated based on the amount of space a grid has; but if a grid also uses other forms of the GridLength values, they will take precedence when the space is calculated.

But, what if you want one column to always have, for example, twice the space as another column? This is when multiplier star sizing comes into the picture. Take a look at the following code snippet:

<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>

Can you notice the first column has a number before the star? That means it would take n times the space as the other column. You aren't limited to whole numbers when using a multiplier with star sizing. You can also define a column to be half the size of other columns by using 0.5 as the multiplier. Using a multiplier with star sizing is the perfect way to make sure a specific area of the grid is always n times larger or smaller than the other star-sized areas of the grid.

The following screenshot shows the result of our grid using the ColumnDefinitions property from the preceding code snippet:

Star sizing

Absolute sizing

Absolute sizing, as the name implies, is used when you wish to give a column or a row a fixed size in pixels. The pixel value is of the double type, which means you are not limited to a value of a whole number, and you can use a floating point as your value as well. The value you set using the absolute sizing is fixed, and it won't change regardless of whether the content of the row or column is larger in size than the space you allocated to it. If, for example, you put a button with the height of 40 pixels into a fixed-size row with the height of 20 pixels, the button will get cut off. Absolute sizing takes precedence over the other two sizing options and it is always the first one to get calculated.

The following code snippet demonstrates how to set up a row with the height of 40 pixels using absolute sizing:

<Grid.RowDefinitions>
<RowDefinition Height="40"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>

Auto sizing

Auto sizing is the last of the three possible options of GridLength. When a row or column size is set using the auto sizing option, the size of the row or column will be primarily dictated by the content within it. Why primarily? Because other than content, the following factors take part in calculating a row or column that is auto sized:

  • In an auto-sized row or column, the largest element in that row or column dictates its height or width.
  • Unless you specifically state a sizing option for the last row of a grid, all the remaining space will be allocated to it.

To use auto sizing, all you have to do is assign a value of Auto to the Height or Width properties of a row or column in your grid. In the following screenshot, two rows were defined with the auto sizing option. Notice how the larger button dictates the height of the row and how the remaining space is just allocated for the last row of the grid, regardless of the content inside of it:

Auto sizing

Placing content into a grid

Now that we have understood how to size up our grid, it's time to put some content into it. Before we begin, make sure the code for your grid is as follows:

<Grid x:Name="LayoutRoot" Background="White" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
</Grid>

If you are unsure about any of the sizing in this code, please refer to the previous section.

Positioning an element within a grid is done by using the following four attached properties:

  • Row: The grid row in which the element will be positioned
  • Column: The column in which the element will be positioned
  • RowSpan: The amount of rows an element will be spanned over
  • ColumnSpan: The amount of columns an element will be spanned over

    Note

    Attached properties are a specialized kind of properties that give a child element the ability to specify a value for a property that is actually defined in another element, which is mostly their parent element. Attached properties have a very easy-to-spot syntax—TypeName.AttachedProperty. The primary use of attached properties is for layout purposes, but attached properties can also be found in Silverlight's animation engine and other places within the Silverlight framework. An example of an attached property can be Grid.Row, where Grid is the type and Row is the name of the attached property.

Numbering of rows and columns begins at 0, and if you don't specify any value to an element within the grid, it will default to the first row (0) and the first column (again, 0).

Let's add an image to the first row of our grid but on the second column (remember: our grid is divided into two rows and two columns with different-sized schemes). Copy the following line of code to your project, just below the closing Grid.ColumnDefinitions tag:

<Image Source="http://www.packtpub.com/sites/default/files/banners/ Learning%20jQuery%201.3.jpg" Grid.Row="0" Grid.Column="1" />

Recognizing the attached properties? Using Grid.Row and Grid.Column, we told our new image element that we want to position it in the first row and the second column. The result should look like the following screenshot:

Placing content into a grid

To stretch the image across both columns we simply replace the Grid.Column attached property with the Grid.ColumnSpan attached property and provide it with the number of columns we wish to span across as the value. Setting the Grid.ColumnSpan property with the value of 2 will give the result, as shown in the following screenshot:

Placing content into a grid

To demonstrate the RowSpan property, change the value of the first row's height from Auto to 30, so it will have a valid height; and change the Image element as follows:

<Image Source="http://www.packtpub.com/sites/default/files/banners/ Learning%20jQuery%201.3.jpg" Grid.RowSpan="2" Stretch="UniformToFill" />

The preceding line of code sets the image to span over two rows and sets its stretching mode to UniformToFill, so it would fill all the available space. This change will result in the following screenshot:

Placing content into a grid

Our image now spans over two rows, each having 30 pixels of height, and as we have set its Stretch property to UniformToFill, it also fills up all the available space.

Changing the grid layout dynamically

When we were introduced to XAML in the previous chapter, we looked at everything that could be done with it and also how it could be done in code, which is not as easy. While designing our grid is usually done in XAML, there may be times when you wish to add rows or columns dynamically using code. The process involves exactly two lines of code—one for defining the RowDefinition or ColumnDefinition object, and the other for actually adding that new definition to our grid. Let's add a new row to our grid (which is named LayoutRoot) dynamically. In Visual Studio 2010, right-click on MainPage.xaml and click on View Code. Add the following code snippet right after InitializeComponet() in the MainPage constructor method:

RowDefinition myNewRow = new RowDefinition();
LayoutRoot.RowDefinitions.Add(myNewRow);

The first line of code defines a new RowDefinition object and the second line adds the new row definition to the grid's row definitions collection using the Add method.

Build and run the application, and you should see the new row added to your grid.

Note

Adding a column definition works exactly the same way, but instead of defining a RowDefinition object, we define a ColumnDefinition object. The same goes for adding it to the grid; instead of adding the new column to the RowDefinitions collection, we add it to the ColumnDefinitions object.

To remove a row or column, we use the same scheme. First, we declare a row or column we wish to remove, and then we tell the grid control to remove it from the collection. The following code snippet will remove the last row from a grid:

int lastRowIndex = LayoutRoot.RowDefinitions.Count - 1;
RowDefinition rowToDelete = LayoutRoot.RowDefinitions[lastRowIndex];
LayoutRoot.RowDefinitions.Remove(rowToDelete);

The first line of code specifies which row we wish to delete. As we want to delete the last row of the grid, we can count the number of rows in the grid and subtract 1 (remember, collections start with index 0). Once we have the index number, we get the desired RowDefinition object from the collection, and finally we remove that RowDefinition object from the collection using the Remove method.

StackPanel

StackPanel is one of the easier layout controls to use. The StackPanel control is used when you wish to position the elements in a horizontal or vertical layout spanning across a single row or column. Using StackPanel is very straightforward. The following code snippet demonstrates how to use it:

<StackPanel>
<Rectangle Fill="#ff80bca3" Height="20" />
<Rectangle Fill="#fff6f7bd" Height="20" />
<Rectangle Fill="#ffe6ac27" Height="20" />
</StackPanel>

The preceding XAML code demonstrates the use of a StackPanel control with three 20-pixel high rectangles inside of it. It will render as follows:

StackPanel

The StackPanel control's default orientation is to vertically align its child controls, but by specifying the orientation to horizontal, StackPanel is capable of arranging its controls horizontally. The following code snippet changes the orientation of StackPanel:

<StackPanel Orientation="Horizontal" Height="60">
<Rectangle Fill="#ff80bca3" Width="33" />
<Rectangle Fill="#fff6f7bd" Width="33" />
<Rectangle Fill="#ffe6ac27" Width="33" />
</StackPanel>

The preceding code snippet will render as follows:

StackPanel

Nesting layout controls is an important concept that you should always keep in mind. While there is no shame in nesting a StackPanel control inside other StackPanel controls, you should always make sure there is no better suited layout control for your desired layout.

Canvas

Imagine yourself sitting in art class. A blank drawing board is positioned in front of you. As an artist you have the freedom to draw (or position) anything you want anywhere on the drawing board. This is what the Canvas layout inspires to mimic. The Canvas layout is the highest performing layout panel in Silverlight, and its purpose is to provide you with a freeform layout environment for your UI needs. Using the Canvas control will look familiar to anyone, who's been doing HTML. We control how far from the left and how far from the top an object will be placed.

In your Silverlight application, replace the LayoutRoot node with the following code snippet:

<Canvas x:Name="LayoutRoot" Background="White">
<TextBlock Text="Look ma! I'm at the default position!"/>
</Canvas>

Build and run your application, and you should see that the text is positioned at the top-left corner.

Note

Unless specified, the Canvas element will position the added child controls to the top-left corner, as this is the beginning of the positioning scheme. We will shortly discuss how to move an element further to the right, left, top, or bottom.

Controlling the position of an element inside the canvas is done by using the following three attached properties:

  • Left: This is a value, in pixels, that specifies how far an element should be positioned from the left border of the canvas. A positive value moves the element away from the left border (in other words, it moves an element to the right), a negative value moves the element closer to the left border.
  • Top: This is a value, in pixels, that specifies how far an element should be positioned from the top border of the canvas. A positive value moves the element away from the top border (down) while a negative value moves the element closer to the top border (up).
  • ZIndex: This controls the stacking order of elements. The bigger an element's ZIndex value is, the closer that element is to the foreground. In simple words, if two elements are positioned in the same place, the element whose ZIndex property is higher will be on top of the other element.

Note

It's important to know that even though ZIndex is an attached property of Canvas, it works with other panels such as Grid as well. Keep in mind that ZIndex is only relative to the panel that it is set upon and not the entire application.

To demonstrate the use of the Canvas properties, replace the content of your canvas with the following code snippet:

<Rectangle Height="60" Width="60" Fill="Blue"/>
<Rectangle Height="60" Width="60" Fill="Red" Canvas.Left="10" Canvas.Top="20"/>

Build and run your application, and you should get the result, as shown in the following screenshot:

Canvas

As expected, the red rectangle is 10 pixels to the right-hand side of the left border and 20 pixels down from the top border of the blue rectangle. The red rectangle is on top of the blue one, because it was declared after the blue rectangle. To draw the blue rectangle on top of the red one, change the blue rectangle declaration as follows:

<Rectangle Height="60" Width="60" Fill="Blue" Canvas.ZIndex="2"/>

Build and run your application, and you should see the blue rectangle is now on top of the red one. Because, the blue rectangle's ZIndex property has a higher value than the red one (which uses the default 0), it is drawn on top of it.

Setting the Canvas properties from code behind

While this topic is out of the scope of this book, it is entirely possible to set an element's Top, Left, or ZIndex properties using code as well. When you wish to set one of the Canvas properties on an element from code behind, you should use the Canvas static class and then either the SetLeft, SetTop or SetZIndex methods. The following code will move an element 20 pixels to the right using code:

Canvas.SetLeft(blueRectangle, 20);

The syntax is quite simple. The first argument we pass is the name of the UI element we wish to set the property to, for example blueRectangle. The second argument we pass is the value (or amount) we wish to set. In our example, we use the SetLeft method of the Canvas static class to set the blueRectangle element 20 pixels to the right. Wish to set it 20 pixels to the left? No problem! Just set the value of the second argument to -20. Because, the value property is of the double type, we are not limited to whole numbers only.

Border

The Border control is one of the simplest layout controls, and its job is to add a border to its child element. The Border control can hold exactly one child element at a time and while this seems limiting, just remember that this one child element can also be another layout panel, such as Grid or StackPanel. Using the Border control usually involves the BorderBrush and BorderThickness properties. BorderBrush dictates the color of the border, which can be one of the color enumerators (Red, Green, and so on) or the hex value of a color (ARGB—Alpha, Red, Green, and Blue). You could also use LinearGradientBrush for your BorderBrush value, but that means that you will have to use BorderBrush as an Element property. To see an example of this approach, have a look at Silverlight Show's border article located at http://www.silverlightshow.net/items/Using-the-Border-control-in-Silverlight-2-Beta-1-.aspx. The BorderThickness property dictates how wide the border will be. If you set one value for this property (for example, 4), then all four sides of the border will have the width of 4 pixels, but if you wish to have a different width for each side of the Border control, you need to supply four values for this property, separated with a space. To demonstrate this, replace the Canvas element in your Silverlight application with the following code snippet:

<Border BorderBrush="Black" BorderThickness="4 10 4 10" >
<Image Source="http://www.packtpub.com/sites/default/files/banners /Learning%20jQuery%201.3.jpg" Stretch="UniformToFill"/>
</Border>

Build and run your application, and you should see the result, as shown in the following screenshot:

Border

The left and right borders of the image are 4 pixels wide while the top and bottom are 10 pixels wide.

ScrollViewer

The ScrollViewer control has one purpose in life; to scroll content. Imagine you have built a gorgeous dashboard application for your office. On your 23-inch wide screen, the dashboard is shown well, but the boss's secretary's monitor is smaller and uses a lower resolution and, thus, your gorgeous dashboard is cut off and looks weird. To make sure your application will fit all screen sizes, you can use the ScrollViewer control. With the ScrollViewer control in hand, you have the full control on both the horizontal and vertical scroll bars. Controlling the scroll bars is done via two properties—HorizontalScrollBarVisibility and VerticalScrollBarVisibility. Possible values for these properties are—Auto, Disabled, Hidden, and Visible. To demonstrate the ScrollViewer control, replace the code for Border with the following code snippet:

<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Image Source="http://www.packtpub.com/sites/default/files/banners /Learning%20jQuery%201.3.jpg" Stretch="UniformToFill" Width="1000" Height="1000"/>
</ScrollViewer>

Build and run your application. If your browser's window dimensions are smaller than 1000 pixels, you should get the result, as shown in the following screenshot:

ScrollViewer

If you play around with the browser's dimensions, you will see that the scroll viewer automatically adjusts its scroll bars as well.

The larger the window size is, the shorter the scroll bars are, and vice versa of course.

Let's assume we wish to hide the vertical scroll bar, no matter what the size of the window is. All we have to do is change the value for the VerticalScrollBarVisibility property from Auto to Hidden.

ViewBox

If you're coming from a WPF background, the ViewBox control should look familiar to you, as it's been part of WPF since the beginning. If not, don't worry; you'll know all about ViewBox in a second. The main purpose of the ViewBox control is to scale its child control's content to the full available space that the ViewBox control itself is occupying. That means that if the ViewBox control is occupying the width of 300 pixels and height of 300 pixels, any control we will place inside of it will also scale to occupy the same dimensions. If at any point, we resize the ViewBox control, the content inside of it will resize as well. To demonstrate the control, replace the code for ScrollViewer with the following code snippet:

<Viewbox>
<TextBlock Text="Look ma! I can stretch!"/>
</Viewbox>

Build and run your application. As you play around with the browser's window size, you will notice that the text inside the TextBlock control is always positioned at the center of the window, and that the text shrinks and grows as you change the size of the window, as shown in the following two screenshots:

ViewBox
ViewBox

Controlling the visibility

Every UI element in Silverlight, be it TextBox, an image, or even a layout control have the ability to be visible or hidden. We control the visibility of an element using the Visibility property. Visibility has two possible values—Visible (default) or Collapsed. It is important to remember that if an element's visibility property is set to Collapsed, that element will not render on the page and, thus, won't take up any space. To read more about visibility, please visit the UIElement.Visibility Property page on MSDN at http://msdn.microsoft.com/en-us/library/system.windows.uielement.visibility%28v=vs.95%29.aspx.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.138.104