CHAPTER 14 SILVERLIGHT INTRODUCTION 338 6. Open up ~/App.xaml. 7. Inside the <Application.Resources> block, enter the following: <Style x:Key="MyStyle" TargetType="TextBlock"> <Setter Property="FontFamily" Value="Comic Sans MS"/> <Setter Property="FontSize" Value="54"/> <Setter Property="Foreground" Value="#FF0000FF"/> </Style> 8. Now go back to MainMenu.xaml and find the line where it says the following: <TextBlock FontSize="40" Canvas.Left="200" Canvas.Top="25">Silverlight Demo</TextBlock> 9. Add the following attribute to this tag to reference the style you created in App.xaml: Style="{StaticResource MyStyle}" Your tag should now look like this: <TextBlock FontSize="40" Canvas.Left="200" Canvas.Top="25" Style="{StaticResource MyStyle}">Silverlight Demo</TextBlock> APPLICATION.RESOURCES The Application.Resources section allows you to hold much more complex styles than you have just created. It can be used to hold pretty much any set of properties you might want to reuse. For example, you could include colors, gradients, or even control templates. Positioning Elements One of the most confusing parts of Silverlight and WPF is element positioning. When you start working with Silverlight and WPF, it is quite common to find yourself wondering why an element is not displaying. This is normally due to the following: • You haven’t set the width or height. • Your element is obscured by another element. • You have positioned the element off the screen. • Your element is transparent. Silverlight positions elements using two axes running from the top-left corner of the screen called Left (horizontal axis) and Top (vertical axis). The top-left corner is referred to as coordinates 0, 0 (see Figure 14-6). CHAPTER 14 SILVERLIGHT INTRODUCTION 339 Figure 14-6. Silverlight screen coordinates system You are probably expecting to be able to position elements in Silverlight similar to the following code: <TextBlock Left="10" Top="20"></TextBlock> However, elements are positioned using the Canvas.Left and Canvas.Top properties (unless positioned through some other means such as a Grid): <TextBlock Canvas.Left="10" Canvas.Top="20"></TextBlock> Canvas.Left and Canvas.Top are a special type of property called an attached property. The Left and Top properties are actually attached to the Canvas element. This means you are positioning the TextBlock relative to the Canvas element. This is an important concept to understand and brings you to the subject of attached and dependency properties. Attached and Dependency Properties When you set a property of an object in ASP.NET such as Width on a TextBox, you would usually write something like this: <asp:TextBox Width=“300" Runat="server" /> Behind the scenes, the Width value is retained in a private field. If you were to retrieve the Width property, it would be the same as when it was first set. However, when working with dependency properties, this is not necessarily true. CHAPTER 14 SILVERLIGHT INTRODUCTION 340 Consider how a browser works out where to display an item on the screen. It is not as straight forward as it first sounds. There are actually a number of things that need to be taken into account when calculating where an item will be positioned on a page: • Other elements on the page • Runtime settings (e.g., screen and browser settings) • Styles • Templates That’s quite a lot to consider. You could say the positioning is dependent on lots of other factors. Dependency properties are properties that are dependent on other property values. It’s as simple as that and it saves you lots of work, and not just for tasks such as positioning elements. Dependency properties are also used for tasks such as data binding where Silverlight needs to know to redraw an item if the underlying data source were to change. A predefined order exists that determines how dependency properties will be evaluated, which is intuitive for the most part. For more information on how dependency properties are evaluated, please refer to http://msdn.microsoft.com/en-us/library/ms743230.aspx. Attached properties are a type of dependency property, but attached properties do not necessarily exist in the object they are set on. They are easy to spot because are written in this format: AttachedPropertyProvider.PropertyName With the theoretical stuff out the way let’s look at the controls that allow you to position elements on a page. Layout Controls The main layout controls in Silverlight are the following: • Canvas • StackPanel • Grid Canvas Canvas is the simplest of all the layout controls. You can think of it as a rectangle or div tag in which you put content. Content added to a canvas is normally then positioned absolutely by setting the Canvas.Left and Canvas.Top properties. Canvas is unique from the other layout controls in that it is the only layout control that allows you to modify the Z index (or which elements on top of which). Stack Panel Stack panels allow you to set items positioned within them to flow horizontally or vertcially by setting a property called Orientation to either Vertical or Horizontal (see Figure 14-7). CHAPTER 14 SILVERLIGHT INTRODUCTION 341 Figure 14-7. Diagram of a stack panel set to vertical and horizontal alignment Let’s create an example stack panel now: 1. Right-click the project and add a new folder called Layout. 2. Right-click and select Add➤New Item. 3. Select Silverlight User Control. 4. Name the control StackPanelTest. 5. Add the following XAML inside the LayoutRoot Grid tag (make sure to alter the width and height, or you will not see the whole column): <StackPanel Orientation="Vertical" Width="200" Height="500"> <Rectangle Fill="blue" Width="100" Height="100"></Rectangle> <Rectangle Fill="Red" Width="100" Height="100"></Rectangle> <Rectangle Fill="Yellow" Width="100" Height="100"></Rectangle> <Rectangle Fill="Green" Width="100" Height="100"></Rectangle> </StackPanel> You now need to modify the MainMenu control to enable it to take you to the stack panel page you have just created. Wiring up a button in Silverlight is similar to performing the same task in ASP.NET or Windows forms. You need to wire up an event in the page loaded event because the button won’t be created until this point. CHAPTER 14 SILVERLIGHT INTRODUCTION 342 1. Open MainMenu.xaml.cs. 2. Add an event handler for when the MainMenu is loaded in the MainMenu constructor: public MainMenu() { InitializeComponent(); this.Loaded += new RoutedEventHandler(MainMenu_Loaded); } 3. In MainMenu_Loaded() add the following code: void MainMenu_Loaded(object sender, RoutedEventArgs e) { this.cmdStackPanel.Click += new RoutedEventHandler(cmdStackPanel_Click); } 4. Now create a method to be called when cmdStackPanel is clicked: void cmdStackPanel_Click(object sender, RoutedEventArgs e) { PageNavigator.LoadPage(new Layout.StackPanelTest()); } Your code should now look similar to the following: public partial class MainMenu : UserControl { public MainMenu() { InitializeComponent(); this.Loaded += new RoutedEventHandler(MainMenu_Loaded); } void MainMenu_Loaded(object sender, RoutedEventArgs e) { this.cmdStackPanel.Click += new RoutedEventHandler(cmdStackPanel_Click); } void cmdStackPanel_Click(object sender, RoutedEventArgs e) { PageNavigator.LoadPage(newLayout.StackPanelTest()); } } Now press F5 to run the application. Click the Stack Panel button and you should see a screen similar to Figure 14-8. CHAPTER 14 SILVERLIGHT INTRODUCTION 343 Figure 14-8. Laying out items with the StackPanel Try changing the Orientation of the StackPanel to Horizontal to see how it affects the positioning of the squares. StackPanel is a very useful control and is very flexible. It is used extensively to perform tasks such as laying out lists of elements and creating menus. Grid The Grid layout control allows you to define a grid strucure to place individual elements within and is in some ways similar to an HTML table. You will create a 2 x 2 grid and some colored rectangles and then position them within the grid: 1. Right-click the Layout folder and select Add➤New Item➤Silverlight User Control. 2. Name it GridTest. 3. Enter the following XAML between the Grid tags (note that the Grid was defined first, and then the Grid.Row and Grid.Column attached properties are added to position the elements): <Grid.RowDefinitions> <RowDefinition Height="150"></RowDefinition> <RowDefinition Height="150"></RowDefinition> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="300"></ColumnDefinition> <ColumnDefinition Width="300"></ColumnDefinition> </Grid.ColumnDefinitions> CHAPTER 14 SILVERLIGHT INTRODUCTION 344 <Rectangle Fill="blue" Grid.Row="0" Grid.Column="0" Width="100" Height="100"></Rectangle> <Rectangle Fill="Red" Grid.Row="0" Grid.Column="1" Width="100" Height="100"></Rectangle> <Rectangle Fill="Yellow" Grid.Row="1" Grid.Column="0" Width="100" Height="100"></Rectangle> <Rectangle Fill="Green" Grid.Row="1" Grid.Column="1" Width="100" Height="100"></Rectangle> 4. Let’s add the ability to navigate to this page on the main menu. Open ~/MainMenu.xaml.cs. 5. Add the following code to the MainMenu_Loaded() method: this.cmdGrid.Click += new RoutedEventHandler(cmdGrid_Click); 6. Add the following event handler: void cmdGrid_Click(object sender, RoutedEventArgs e) { PageNavigator.LoadPage(new Layout.GridTest()); } 7. Press F5 to run the application you should see a page like Figure 14-9. Figure 14-9. Grid Layout control . Orientation="Vertical" Width=" 200 " Height=" 500 "> <Rectangle Fill="blue" Width=" 100 " Height=" 100 "></Rectangle> <Rectangle. Width=" 100 " Height=" 100 "></Rectangle> <Rectangle Fill="Yellow" Grid.Row="1" Grid.Column=" ;0& quot; Width=" 100 " Height=" 100 "></Rectangle>. Fill="Red" Width=" 100 " Height=" 100 "></Rectangle> <Rectangle Fill="Yellow" Width=" 100 " Height=" 100 "></Rectangle>