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:
- Stuff you can do in either code or XAML.
- Stuff you can do only in code (e.g., event handling and methods).
- 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 the
TextBlock 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 TextBlock
element now contains three types of
identifiers:
- TextBlock is an object element-a
.NET object based on an XML element.
Text and Foreground are
property attributes-.NET properties set with XML
attributes.
- 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"
/>
<GradientStop
Offset="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:
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: