Resources
Resources are named chunks of data defined separately from code
and bundled with your application or component. .NET provides a great deal of
support for resources , a bit of which we already
used when we referenced tom.png from our XAML button earlier in this
chapter. WPF also provides special support for resources scoped to elements
defined in the tree.
As an example, let's declare some default instances of our
custom Nickname objects in XAML in
Example 1-32.
Example 1-32. Declaring objects in XAML
<!-- Window1.xaml -->
<?Mapping XmlNamespace="local" ClrNamespace="DataBindingDemo" ?>
<Window
x:Class="DataBindingDemo.Window1"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
xmlns:local="local"
Text="Nicknames">
<Window.Resources>
<local:Nicknames x:Key="names">
<local:Nickname Name="Don" Nick="Naked" />
<local:Nickname Name="Martin" Nick="Gudge" />
<local:Nickname Name="Tim" Nick="Stinky" />
</local:Nicknames>
</Window.Resources>
<DockPanel DataContext="{StaticResource names}">
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<TextBlock VerticalAlignment="Center">Name: </TextBlock>
<TextBox Text="{Binding Path=Name}" />
<TextBlock VerticalAlignment="Center">Nick: </TextBlock>
<TextBox Text="{Binding Path=Nick}" />
</StackPanel>
...
</DockPanel>
</Window>
Notice the Window.Resources, which is property-element
syntax to set the Resources property of the Window1 class.
Here, we can add as many named objects as we like, with the name coming from
the Key attribute and the object coming from the XAML elements
(remember that XAML elements are just a mapping to .NET class names). In this
example, we're creating a Nicknames collection named names to hold
three Nickname objects, each constructed with the default constructor,
and then setting each of the Name and Nick properties.
Also notice the use of the StaticResource markup
extension to reference the names resource as the collection to use for
data binding. With this XAML in place, our window construction reduces to the
code in Example 1-33.
Example 1-33. Finding a resource in code
public partial class Window1 : Window {
Nicknames names;
public Window1( ) {
InitializeComponent( );
this.addButton.Click += addButton_Click;
// get names collection from resources
this.names = (Nicknames)this.FindResource("names");
// no need to make data available for binding here
//dockPanel.DataContext = this.names;
}
void addButton_Click(object sender, RoutedEventArgs e) {
this.names.Add(new Nickname( ));
}
}
Now instead of creating the collection of names, we can pull it
from the resources with the FindResource method. Just because this
collection was created in XAML doesn't mean that we need to treat it any
differently than we treated it before, which is why the Add button
event handler is the exact same code. Also, there's no need to set the data
context on the dock panel, because that property was set in the XAML.
1.8.1. XAML Mapping Syntax
Before we go on with resources, we need to discuss a new XAML
syntax that's come up, the mapping syntax
. The XAML mapping syntax provides the ability to bring in types not already
known by the XAML compiler. Our use of the mapping syntax looks like
Example 1-34.
Example 1-34. XAML mapping syntax
<?Mapping XmlNamespace="local" ClrNamespace="DataBindingDemo" ?>
<Window
x:Class="DataBindingDemo.Window1"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
xmlns:local="local"
Text="Nicknames">
<Window.Resources>
<local:Nicknames x:Key="names">
...
</Window.Resources>
...
</Window>
When bringing in a new type in XAML, we have to do a two-step
mapping. The first step is to map a CLR namespace to an XML namespace. That's
what the <?Mapping ... ?> line does. The second step is to map
the XML namespace to a namespace prefix, which is what the xmlns:local
attribute establishes. I've used local for both the XML namespace and
prefix. I've chosen local because the CLR namespace to which I'm
referring must be part of the assembly being compiled along with the XAML in
question. You can import CLR namespaces for another assembly by specifying the
optional Assembly attribute as part of the mapping, as
Figure 1-17 shows.
 |
As of the current build at the time of writing,
when you're using a mapping directive in a XAML file, you must also specify a
UI culture in the .csproj file, which
you can do by adding a UICulture property to a PropertyGroup element,
e.g.:
<!-- DataBindingDemo.csproj -->
<Project ...>
<PropertyGroup>
<UICulture>en-US</UICulture>
...
</PropertyGroup>
...
</Project>
|
|
With the mapping completed, you're able to use the XML namespace
prefix in front of any class with a default constructor to create an instance
of it in a XAML file.
For the full scoop on resources, including resource scoping and
lookup, as well as using them for theming and skinning, read
Chapter 6.
 |