Example: Binding to a static resource of simple String:
Let’s start simply, just binding to a string defined as a static resource in a ResourceDictionary:
<UserControl x:Class="SilverlightApplication10.UserControl4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Width="200" Height="250">
<UserControl.Resources>
<!-- A simple resource: just a string -->
<sys:String x:Key="aSingleString">SkySigal</sys:String>
</UserControl.Resources>
<Grid>
<!-- Binding to the resource's representation as a string -->
<TextBlock Margin="0,0"
Text="{Binding Source={StaticResource aSingleString}}" />
<!-- Binding to the resource's Path property -->
<TextBlock Margin="0,16"
Text="{Binding Source={StaticResource aSingleString}, Path=Length}"/>
</Grid>
</UserControl>
Things to notice:
- XAML doesn’t know about strings off the bat, so an xmlns has to be defined to point to the framework’s mscorelib assembly:
xmlns:sys="clr-namespace:System;assembly=mscorlib"
- Once the sys namespace has been defined, we could use it to define the static resource, tagged with an x:Key attribute:
<sys:String x:Key="aSingleString">SkySigal</sys:String>
- We refer back to this static resource with the {staticResource…} tag, pointing to the key of the resource:
Text="{Binding Source={StaticResource aSingleString}}"
- We can refer to a property of the static resource, using the Path attribute:
Text="{Binding Source={StaticResource aSingleString}, Path=Length}"
Example: Binding to a static resource of a single instance of a custom class:
You’re not stuck with only using classes defined in the framework. For example, if you have defined a class Person:
namespace SilverlightApplication10 {
public class Person {
public string FirstName { get; set; }
public int Girth { get; set; }
}
}
You just repeat the same recipe, first defining a namespace, declaring the instance, and then referring to the instance:
<UserControl x:Class="SilverlightApplication10.UserControl11"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:SilverlightApplication10"
Width="200" Height="200">
<UserControl.Resources>
<local:Person x:Key="aSinglePerson" FirstName="John" Girth="104"/>
</UserControl.Resources>
<Canvas Background="White">
<TextBlock
Text="{Binding Source={StaticResource aSinglePerson}, Path=FirstName}"/>
</Canvas>
</UserControl>
Notice how we did basically the same thing as in the last example:
- First we ensure that we had a xml namespace pointing to the relevant C# namespace:
xmlns:local="clr-namespace:SilverlightApplication10"
- Then we instantiate a local resource using that xml namespace:
<local:Person x:Key="aSinglePerson" FirstName="John" Girth="104"/>
- Finally, we bind to the StaticResource:
<TextBlock Text="{Binding Source={StaticResource aSinglePerson}, Path=FirstName}"/>
If we had not used the Path= attribute, the returned value would have defaulted to the result of Person.ToString(), and would have looked like:
SilverlightApplication10.Person
Very Important:
Note how the the Person property was for FirstName, and not just Name.
Silverlight, and WPF, get confused if you refer to a class whose property is called Name, because it defaults to x:Name / Name.
If you use Name, it won’t compile and just jams up. I don’t currently know of a way around this bug.
Example: Binding to a static resource of a collection of custom instances:
If we go back and define another class that the XAML can refer to, this time a collection of Person items, called Persons:
namespace SilverlightApplication10 {
// One person:
public class Person {
public string FirstName { get; set; }
public int Girth { get; set; }
}
//A collection of persons:
public class Persons : List<Person> {
public Persons() {
this.Add(new Person() { FirstName = "John", Girth = 60 });
this.Add(new Person() { FirstName = "Betty", Girth = 30 });
}
}
}
we can update our XAML to instantiate and use it like this:
<UserControl x:Class="SilverlightApplication10.UserControl4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:SilverlightApplication10"
Width="200" Height="250">
<UserControl.Resources>
<local:Person x:Key="aSinglePerson" FirstName="John" Girth="104"/>
<local:Persons x:Key="somePersons"/>
</UserControl.Resources>
<Grid Background="White">
<!-- Binding to the resource's FirstName property -->
<TextBlock Margin="0,32"
Text="{Binding Source={StaticResource aSinglePerson}, Path=FirstName}"/>
<!-- Two ways of doing the same thing - binding to list as src for Items -->
<ListBox Margin="0,135,0,50" ItemsSource="{StaticResource somePersons}"/>
<!-- But this allows you to specify look of item and what its bound to -->
<ListBox Margin="0,60,0,120" >
<ListBox.ItemsSource>
<Binding Source="{StaticResource somePersons}" />
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=FirstName}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
The things to notice here are:
- Once again, we start by importing a usable namespace:
xmlns:local="clr-namespace:SilverlightApplication10"
- Making a static resource:
<local:Persons x:Key="somePersons"/>
- Which we we use as the data source for the listbox:
<ListBox Margin="0,135,0,50" ItemsSource="{StaticResource somePersons}"/>
- But in this case, we defer the Path= definition to the actual binding, item by item:
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=FirstName}"/>
</DataTemplate>
</ListBox.ItemTemplate>
Example: Binding to a static resource of a collection of strings
You may be wondering at this point how you can bind to a simple list of string…rather than having to go through all this extra work of defining a collection class, etc.
In WPF you can use the x:Array tag (I wouldn’t at this time, as its unique to WPF), or you can import the System.Collections namespace in order to make a collection of Strings, like this:
<UserControl x:Class="SilverlightApplication10.UserControl4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:SilverlightApplication10"
xmlns:sysCollections="clr-namespace:System.Collections;assembly=mscorlib"
Width="200" Height="250">
<UserControl.Resources>
<!-- An XAML defined collection of strings -->
<sysCollections:ArrayList x:Key="justNames">
<sys:String>Tom</sys:String>
<sys:String>Baby</sys:String>
<sys:String>Mark</sys:String>
<sys:String>Fred</sys:String>
</sysCollections:ArrayList>
</UserControl.Resources>
<Grid Background="White">
<!-- Binding to the list resource's Count property -->
<TextBlock Margin="0,32"
Text="{Binding Source={StaticResource justNames}, Path=Count}" />
<!-- Two ways of doing the same thing - binding to list as src for Items -->
<ListBox Margin="0,60,0,120" >
<ListBox.ItemsSource>
<Binding Source="{StaticResource justNames}" />
</ListBox.ItemsSource>
</ListBox>
<ListBox Margin="0,135,0,50" ItemsSource="{StaticResource justNames}"/>
</Grid>
</UserControl>
Warning:
But the above doesn’t work in Silverlight.
Actually, to be completely clear about this -- while this will appear to work in the IDE (the UserControl will update as you type, and show the results of the Binding, etc.) it will throw an exception when you compile. The reason for the exception is that the Visual Studio IDE is using the full framework’s System.Collection.ArrayList class – but when it tries to compile the above XAML against the SL assemblies, it won’t find the ArrayList class as it has been deprecated by MS and is not part of the SL assemblies.
In other words…it’s all a red herring.
Is there any other solution? Yes.
If you have the Silverlight Toolkit installed you can use the ObjectCollection inside of Microsoft.Windows.Controls like this:
<UserControl x:Class="SilverlightApplication10.UserControl4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:SilverlightApplication10"
xmlns:controls="clr-namespace:Microsoft.Windows.Controls;assembly=Microsoft.Windows.Controls"
Width="200" Height="250">
<UserControl.Resources>
<controls:ObjectCollection x:Key="HardcodedStrings">
<sys:String>Item 1</sys:String>
<sys:String>Item 2</sys:String>
<sys:String>Item 3</sys:String>
</controls:ObjectCollection>
</UserControl.Resources>
...
</UserControl>
Although you should seriously consider if you need to include Microsoft.Windows.Controls if that’s all you need from it (it is 196K after all), when the class, as first described here, is only:
public partial class ObjectCollection : Collection<object> {
#region Constructors
public ObjectCollection() {
}
public ObjectCollection(IEnumerable collection){
foreach (object obj in collection) {
Add(obj);
}
}
#endregion
}//Class:End
In other words, all you have to do is define in your assembly the above class, and use something like the following:
<UserControl x:Class="SilverlightApplication10.UserControl4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:SilverlightApplication10"
Width="200" Height="250">
<UserControl.Resources>
<local:ObjectCollection x:Key="HardcodedStrings">
<sys:String>Item 1</sys:String>
<sys:String>Item 2</sys:String>
<sys:String>Item 3</sys:String>
</local:ObjectCollection>
</UserControl.Resources>
<Grid Background="White">
<!-- Two ways of doing the same thing - binding to list as src for Items -->
<ListBox Margin="0,135,0,50" ItemsSource="{StaticResource HardcodedStrings}"/>
<!-- But this allows you to specify look of item and what its bound to -->
<ListBox Margin="0,60,0,120" >
<ListBox.ItemsSource>
<Binding Source="{StaticResource HardcodedStrings}" />
</ListBox.ItemsSource>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=.}"></TextBlock>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
Edit – An possible improvement: a TypedObjectCollection
If you are interested in how to Type check such collection, check out this post (Silverlight- Using a Typed ObjectCollection).
StaticResource versus DynamicResource
Note that if you are coming from WPF, you need to know that SL 2.0 does not support the {DynamicResource…} Markup Extension
If you don’t know what a DynamicResource is, this is a simple introduction to it (and read the first comment).