Defining Layouts through XAML in Windows Phone 7


This chapter is taken from book "Programming Windows Phone 7" by Charles Petzold published by Microsoft press. http://www.charlespetzold.com/phone/index.html

Silverlight program is generally a mix of code and XAML. Most often, you'll use XAML for defining the layout of the visuals of your application, and you'll use code for event handling, including all user-input events and all events generated by controls as a result of processing user-input events. Much of the object creation and initialization performed in XAML would traditionally be done in the constructor of a page or window class, although XAML is usually concerned with object creation and initialization, certain features of Silverlight provide much more than object initialization would seem to imply.

Experienced programmers encountering XAML for the first time are sometimes resistant to it. I know I was. Everything that we value in a programming language such as C#-required declarations, strong typing, array-bounds checking, tracing abilities for debugging-largely goes away when everything is reduced to XML text strings.

Everything you need to do in Silverlight can be allocated among these three categories:

  1. Stuff you can do in either code or XAML.
  2. Stuff you can do only in code (e.g., event handling and methods).
  3. Stuff you can do only in XAML (e.g., templates).

Property Inheritance

To experiment with some XAML, it's convenient to create a project specifically for that purpose. Let's call the project XamlExperiment, and put a TextBlock in the content grid:

<
Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <
TextBlock Text="Hello, Windows Phone 7!" />
</
Grid>

The text shows up in the upper-left corner of the page's client area. Let's make the text italic. You can do that by setting the FontStyle property in the TextBlock:

<TextBlock Text="Hello, Windows Phone 7!"
     FontStyle="Italic" />

Alternatively, you can put that FontStyle attribute in the PhoneApplicationPage tag:

<phone:PhoneApplicationPage ... FontStyle="Italic" ...

This FontStyle attribute can go anywhere in the PhoneApplicationPage tag.

While keeping the FontStyle property setting to Italic in the PhoneApplicationPage tag, add a FontStyle setting to the TextBlock:

<TextBlock Text="Hello, Windows Phone 7!"
    FontStyle="Normal" />

Now the text in this particular TextBlock goes back to normal.

Property-Element Syntax

Let's remove any FontStyle settings that might stil be around, set theTextBlock attributes to these values:

<TextBlock Text="Hello, Windows Phone 7!"
    FontSize="36"
    Foreground="Red" />

Because this is XML, we can separate the TextBlock tag into a start tag and end tag with nothing in between:

<TextBlock Text="Hello, Windows Phone 7!"
    FontSize="36"
    Foreground="Red">
</TextBlock>

But you can also do something that will appear quite strange initially. You can remove the FontSize attribute from the start tag and set it like this:

<TextBlock Text="Hello, Windows Phone 7!"
    Foreground="Red">
    <TextBlock.FontSize>
         36
    </TextBlock.FontSize>
</TextBlock>

Now the TextBlock has a child element called TextBlock.FontSize, and within the TextBlock.FontSize tags is the value.

This is called property-element syntax, and it's an extremely important part of XAML. The introduction of property-element syntax also allows nailing down some terminology that unites .NET and XML. This single TextBlockelement now contains three types of identifiers:

  1. TextBlock is an object element-a .NET object based on an XML element.

  2. Text and Foreground are property attributes-.NET properties set with XML attributes.
  3. FontSize is now a property element-a .NET property expressed as an XML element.

Colors and Brushes

Let's return the TextBlock to its pristine condition:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <
TextBlock Text="Hello, Windows Phone 7!" />
</
Grid>

The text shows up as white (or black, depending on the theme your selected) because the Foreground property is set on the root element in MainPage.xaml. You can override the user's preferences by setting Background for the Grid and Foreground for the TextBlock:

<Grid x:Name="ContentPanel" Background="Blue" Grid.Row="1" Margin="12,0,12,0">
    <
TextBlock Text="Hello, Windows Phone 7!" />
                   
Foreground="Red">
</
Grid>

The Grid has a Background property but no Foreground property. The TextBlock has a Foreground property but no Background property. The Foreground property is inheritable through the visual tree, and it may sometimes seem that the Background property is as well, but it is not.

With the scRGB color space, you specify values between 0 and 1 that are proportional to light intensity, so the non-linearity of the human eye makes the color seem off. If you really want a medium gray in scRGB you need values much lower than 0.5, such as:

Foreground="sc# 0.2 0.2 0.2"

Let's go back to one TextBlock in the Grid:

<Grid x:Name="ContentPanel" Background="Blue" Grid.Row="1" Margin="12,0,12,0">
    <TextBlock Text="Hello, Windows Phone 7!"
                    Foreground="Red" />
</Grid>

Just as I did earlier with the FontSize property, break out the Foreground property as a property element:

<TextBlock Text="Hello, Windows Phone 7!">
    <TextBlock.Foreground>
        Red
    </TextBlock.Foreground>
</TextBlock>

When you specify a Foreground property in XAML, a SolidColorBrush is created for the element behind the scenes. You can also explicitly create the SolidColorBrush in XAML:

<TextBlock Text="Hello, Windows Phone 7!">
    <TextBlock.Foreground>
        <SolidColorBrush Color="Red" />
    </TextBlock.Foreground>
</TextBlock

You can also break out the Color property as a property element:

<TextBlock Text="Hello, Windows Phone 7!">
    <TextBlock.Foreground>
        <SolidColorBrush>
            <SolidColorBrush.Color>
                Red
            </SolidColorBrush.Color>
        </SolidColorBrush>
    </TextBlock.Foreground>
</TextBlock>

And you can go even further:

<TextBlock Text="Hello, Windows Phone 7!">
    <TextBlock.Foreground>
        <SolidColorBrush>
            <SolidColorBrush.Color>
                <Color>
                    <Color.A>
                        255

                    </Color.A>
                    <Color.R>
                        #FF

                    </Color.R>
                </Color>
            </SolidColorBrush.Color>
        </SolidColorBrush>
    </TextBlock.Foreground>
</TextBlock>

Notice that the A property of the Color structure needs to be explicitly set because the default value is 0, which means transparent.

Let's begin with a simple solid TextBlock but with the Background property of the Grid broken out as a property element:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
   <Grid.Background>
       <SolidColorBrush Color="Blue" />
   </Grid.Background>
   <TextBlock Text="Hello, Windows Phone 7!"
                   Foreground="Red" />
</Grid>

Remove that SolidColorBrush and replace it with a LinearGradientBrush:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <Grid.Background>
        <LinearGradientBrush>
        </LinearGradientBrush>
    </Grid.Background>
    <TextBlock Text="Hello, Windows Phone 7!"
                    Foreground="Red" />
</Grid>

The LinearGradientBrush has a property of type GradientStops, so let's add property element tags for the GradientStops property:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
   <Grid.Background>
       <LinearGradientBrush>
           <LinearGradientBrush.GradientStops>
           </LinearGradientBrush.GradientStops>
       </LinearGradientBrush>
   </Grid.Background>
   <TextBlock Text="Hello, Windows Phone 7!"
                   Foreground="Red" />
</Grid>

The GradientStops property is of type GradientStopCollection, so let's add tags for that:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
   <Grid.Background>
       <LinearGradientBrush>
           <LinearGradientBrush.GradientStops>
               <GradientStopCollection>
               </GradientStopCollection>
           </LinearGradientBrush.GradientStops>
       </LinearGradientBrush>
   </Grid.Background>
    <TextBlock Text="Hello, Windows Phone 7!"
                    Foreground="Red" />
</Grid/>

Now let's put a couple GradientStop objects in there. The GradientStop has properties named Offset and Color:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <Grid.Background>
        <LinearGradientBrush>
            <LinearGradientBrush.GradientStops>
                <GradientStopCollection>
                    <GradientStop Offset="0"Color="Blue" />
                    <GradientStopOffset="1" Color="Green" />
                </GradientStopCollection>
            </LinearGradientBrush.GradientStops>
        </LinearGradientBrush>
    </Grid.Background>
<TextBlock Text="Hello, Windows Phone 7!"
                Foreground="Red" />
</Grid>

And with the help of property elements, that is how you create a gradient brush in markup. It looks like this:

sev1.gif

The Offset values range from 0 to 1 and they are relative to the element being colored with the brush. You can use more than two:

<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    <Grid.Background>
        <LinearGradientBrush>
            <LinearGradientBrush.GradientStops>
                <GradientStopCollection>
                    <GradientStop Offset="0" Color="Blue" />
                    <GradientStop Offset="0.5" Color="White" />
                <GradientStop Offset="1" Color="Green" />
                </GradientStopCollection>
            </LinearGradientBrush.GradientStops>
        </LinearGradientBrush>
    </Grid.Background>
<TextBlock Text="Hello, Windows Phone 7!"
                Foreground="Red" />
</Grid>

Conceptually the brush knows the size of the area that it's coloring and adjusts itself accordingly. LinearGradientBrush derives from GradientBrush. Another class that derives from GradientBrush is RadialGradientBrush. Here's markup for a larger TextBlock with a RadialGradientBrush set to its Foreground property:

<TextBlock Text="GRADIENT" FontFamily="Arial Black" FontSize="72" HorizontalAlignment="Center" VerticalAlignment="Center">
    <TextBlock.Foreground>
        <RadialGradientBrush>
            <RadialGradientBrush.GradientStops>
                <GradientStopCollection>
                    <GradientStop Offset="0" Color="Transparent" />
                    <GradientStop Offset="1" Color="Red" />
                </GradientStopCollection>
            </RadialGradientBrush.GradientStops>
        </RadialGradientBrush>
    </TextBlock.Foreground>
</TextBlock>

And here's what the combination looks like:

sev2.gif