Note: these are early notes based on some initial experiments with the Silverlight 5 beta, apply a pinch of salt to what you read.
There’s another new tweak to the binding engine in Silverlight which now allows for a RelativeSource with a Mode of Ancestor which is something that existed in WPF but wasn’t there in Silverlight.
Let’s say I wanted to produce a data template for a ListBox – a simple scenario such as;
<Grid
x:Name="LayoutRoot"
Background="White">
<ListBox>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock
Text="{Binding}"
FontSize="14" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.Items>
<sys:String>One</sys:String>
<sys:String>Two</sys:String>
<sys:String>Three</sys:String>
</ListBox.Items>
</ListBox>
</Grid>
and imagine that I want the selected ListBox item to be highlighted with a green rectangle or similar. Logically, it feels like I should be able to do something like this;
<Rectangle
Visibility="{Binding IsSelected,Converter={StaticResource converter}}"
Stroke="Green"
StrokeThickness="1"
RadiusX="3"
RadiusY="3" />
but in Silverlight 4 I can’t really get anywhere near the
IsSelected property of the
ListBoxItem that ultimately will contain my content. Instead I need to go and visit the
ItemContainerStyle of the
ListBox and then re-template the
ListBoxItem within there in order to make this work and it all feels a little cumbersome.
In Silverlight 5, I can get much closer. I know that this template is used in a ListBox so I know that I will end up contained in a ListBoxItem and so I should be able to make use of that as in;
<DataTemplate>
<Grid>
<Rectangle
Visibility="{Binding
RelativeSource={RelativeSource AncestorType=ListBoxItem},
Path=IsSelected,
Converter={StaticResource converter}}"
Stroke="Green"
StrokeThickness="1"
RadiusX="3"
RadiusY="3" />
<TextBlock
Text="{Binding}"
FontSize="14"
Margin="3" />
</Grid>
and that
RelativeSource binding is going to searching up the hierarchy looking for a
ListBoxItem and when it finds one it picks up its
IsSelected property and lets me bind to it. Nice
There’s also the AncestorLevel property on the RelativeSource extension which allows you to skip the first N instances of the particular AncestorType that are found in the hierarchical tree “above” your usage of the extension just in case you want to pick out an ancestor at a particular level.
Similarly, I was working on a demo for MIX the other week and I had produced a UserControl. Onto this UserControl I’d added a dependency property called Rating and within the control I needed to be able to bind to that property. Here’s a snippet of XAML from that UserControl;
<UserControl
Name="uc1">
<Image
x:Name="ratingImage"
Margin="8"
Grid.Row="1"
Stretch="Fill"
Source="{Binding ElementName=uc1,Path=Rating,
TargetNullValue={StaticResource imgSatUnsure},
Converter={StaticResource ratingImageConverter}}" />
</UserControl>
and so in this particular situation I wanted my
Image to be able to bind to the
Rating property on my
UserControl and the most convenient way I found of doing that was to name the user control and use
ElementName in order to find the source of my binding.
In Silverlight 5, I could have used RelativeSource as in;
<Image
x:Name="ratingImage"
Margin="8"
Grid.Row="1"
Stretch="Fill"
Source="{Binding
RelativeSource={RelativeSource AncestorType=UserControl},
Path=Rating,
TargetNullValue={StaticResource imgSatUnsure},
Converter={StaticResource ratingImageConverter}}" />
and it would have saved me a tonne of energy as I came across a bug in going via the named route so, again, having another mechanism to reach up the hierarchy and find a particular element would be really useful.
Posted
Tue, Apr 26 2011 12:39 PM
by
mtaulty