Now it's obvious that the Children property is being set twice-and that's
clearly illegal.
Resources Collection
Computer programming is all about the avoidance of repetition. XAML would
seem to be a particularly treacherous area for repetition because it's just
markup and not a real programming language. The most generalized solution to
repetitive markup is the Silverlight style. But a prerequisite to styles is a
more generalized sharing mechanism. This is called the resource, and right away
we need to distinguish between the resources.
XAML resources are always instances of a particular .NET class or structure,
either an existing class or structure or a custom class and the sharing of
resources immediately disqualifies many classes from being defined as XAML
resources.
Here's a Resources collection for a page class that derives from
PhoneApplicationPage:
<phone:PhoneApplicationPage ...>
<phone:PhoneApplicationPage.Resources>
...
</phone:PhoneApplicationPage.Resources>
...
</phone:PhoneApplicationPage>
The resources defined in the Resources collection on a FrameworkElement are
available only within that element and nested elements; the resources defined in
the Application class are available throughout the application.
Sharing Brushes
Let's suppose your page contains several TextBlock elements, and you want to
apply the same LinearGradientBrush to the Foreground of each of them. This is an
ideal use of a resource the resource must be defined before it is used, and it
can only be accessed by the same element or a nested element.
The ResourceSharing project defines all resources and references them in two
TextBlock elements. Here's the complete resource section:
<phone:PhoneApplicationPage.Resources>
<LinearGradientBrush
x:Key="brush">
<GradientStop
Offset="0"
Color="Pink" />
<GradientStop
Offset="1"
Color="SkyBlue" />
</LinearGradientBrush>
<Thickness
x:Key="margin">
12 96
</Thickness>
<system:Double
x:Key="fontsize">
48
</system:Double>
</phone:PhoneApplicationPage.Resources>
The content grid contains the two TextBlock elements:
<Grid
x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<TextBlock
Text="Whadayasay?"
Foreground="{StaticResource
brush}"
Margin="{StaticResource
margin}"
FontSize="{StaticResource
fontsize}"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
<TextBlock
Text="Fuhgedaboudit!"
Foreground="{StaticResource
brush}"
Margin="{StaticResource
margin}"
FontSize="{StaticResource
fontsize}"
HorizontalAlignment="Right"
VerticalAlignment="Bottom" />
</Grid>
The screen shot demonstrates that it works:
x:Key and x:Name
If you need to reference a XAML resource from code, you can simply index the
Resources property with the resource name.
this.Resources["brush"]
If you have resources defined in other Resource collections in the same XAML
file, you can retrieve those as well.
ContentPanel.Resources["margin"]
Introduction to Styles
One very common item in a Resources collection is a Style, which is basically
a collection of property assignments for a particular element type. Besides a
key, the Style also requires a TargetType:
<Style x:Key="txtblkStyle"
TargetType="TextBlock">
...
</Style>
you can use property-element syntax with the Value property
to embed the brush right in the Style
definition. That's how it's done in the Resources
collection of the StyleSharing project:
<phone:PhoneApplicationPage.Resources>
<Style
x:Key="txtblkStyle"
TargetType="TextBlock">
<Setter
Property="HorizontalAlignment"
Value="Center" />
<Setter
Property="VerticalAlignment"
Value="Center" />
<Setter
Property="Margin"
Value="12 96" />
<Setter
Property="FontSize"
Value="48" />
<Setter
Property="Foreground">
<Setter.Value>
<LinearGradientBrush>
<GradientStop
Offset="0"
Color="Pink" />
<GradientStop
Offset="1"
Color="SkyBlue" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</phone:PhoneApplicationPage.Resources>
To apply this style to an element of type TextBlock, set
the Style property (which is defined by FrameworkElement so every kind of element has it):
<Grid
x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<TextBlock
Text="Whadayasay?"
Style="{StaticResource
txtblkStyle}"
HorizontalAlignment="Left"
VerticalAlignment="Top" />
<TextBlock
Text="Fuhgedaboudit!"
Style="{StaticResource
txtblkStyle}"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
/>
</Grid>
The display looks the same as the previous program, which teaches an
important lesson. Notice that values of HorizontalAlignment and
VerticalAlignment are defined in the Style, yet
these are overridden by local settings in the two TextBlock
elements. But the Foreground
set in the Style overrides
the value normally inherited through the visual tree.
Style Inheritance
Styles can enhance or modify other styles through the process of inheritance.
Set the Style property
BasedOn to a previously defined Style.
Here's the Resources collection of the StyleInheritance project:
<phone:PhoneApplicationPage.Resources>
<Style
x:Key="txtblkStyle"
TargetType="TextBlock">
<Setter
Property="HorizontalAlignment"
Value="Center" />
<Setter
Property="VerticalAlignment"
Value="Center" />
<Setter
Property="Margin"
Value="12 96" />
<Setter
Property="FontSize"
Value="48" />
<Setter
Property="Foreground">
<Setter.Value>
<LinearGradientBrush>
<GradientStop
Offset="0"
Color="Pink" />
<GradientStop
Offset="1"
Color="SkyBlue" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
<Style
x:Key="upperLeftStyle"
TargetType="TextBlock"
BasedOn="{StaticResource
txtblkStyle}">
<Setter
Property="HorizontalAlignment"
Value="Left" />
<Setter
Property="VerticalAlignment"
Value="Top" />
</Style>
<Style
x:Key="lowerRightStyle"
TargetType="TextBlock"
BasedOn="{StaticResource
txtblkStyle}">
<Setter
Property="HorizontalAlignment"
Value="Right" />
<Setter
Property="VerticalAlignment"
Value="Bottom" />
</Style>
</phone:PhoneApplicationPage.Resources>
The two new Style definitions at the end override the HorizontalAlignment and
VerticalAlignment properties set in the earlier style.
This allows the two
TextBlock elements to reference these two different
styles:
<Grid
x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<TextBlock
Text="Whadayasay?"
Style="{StaticResource
upperLeftStyle}" />
<TextBlock
Text="Fuhgedaboudit!"
Style="{StaticResource
lowerRightStyle}" />
</Grid>
Themes
Windows Phone 7 predefines many resources that you can use throughout
your application with the StaticResource markup extension. There are predefined colors, brushes,
font names, font sizes, margins, and text styles. Some of them show up
in the root element of MainPage.xaml to supply the defaults for the
whole page:
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource
PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
Gradient Accents
You might want to use the user's preferred accent color in your
program, but as a gradient brush. In other words, you want the same hue,
but you want to get darker or lighter versions. In code, this is fairly
easy by manipulating the red, green, and blue components of the color.
It's also fairly easy in XAML, as the GradientAccent project demonstrates:
<Grid
x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<Grid.Background>
<LinearGradientBrush
StartPoint="0 0"
EndPoint="1 0">
<GradientStop
Offset="0"
Color="White" />
<GradientStop
Offset="0.5"
Color="{StaticResource
PhoneAccentColor}" />
<GradientStop
Offset="1"
Color="Black" />
</LinearGradientBrush>
</Grid.Background>
</Grid>
You can get a more subtle affect by changing the gradient offsets. These can
actually be set outside the range of 0 to 1, perhaps like this:
<LinearGradientBrush
StartPoint="0 0"
EndPoint="1 0">
<GradientStop
Offset="-1"
Color="White" />
<GradientStop
Offset="0.5"
Color="{StaticResource
PhoneAccentColor}" />
<GradientStop
Offset="2"
Color="Black" />
</LinearGradientBrush>
Now the gradient goes from White at an offset of -1 to the accent color at
0.5 to Black at 2. But you're only seeing the section of the gradient between 0
and 1, so the White and Black extremes are not here: