(1 item) |
|
(1 item) |
|
(5 items) |
|
(1 item) |
|
(1 item) |
|
(2 items) |
|
(2 items) |
|
(4 items) |
|
(1 item) |
|
(6 items) |
|
(2 items) |
|
(4 items) |
|
(1 item) |
|
(4 items) |
|
(2 items) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(2 items) |
|
(2 items) |
|
(5 items) |
|
(3 items) |
|
(1 item) |
|
(1 item) |
|
(1 item) |
|
(3 items) |
|
(1 item) |
|
(1 item) |
|
(2 items) |
|
(8 items) |
|
(2 items) |
|
(7 items) |
|
(2 items) |
|
(2 items) |
|
(1 item) |
|
(2 items) |
|
(1 item) |
|
(2 items) |
|
(4 items) |
|
(1 item) |
|
(5 items) |
|
(1 item) |
|
(3 items) |
|
(2 items) |
|
(2 items) |
|
(8 items) |
|
(7 items) |
|
(3 items) |
|
(7 items) |
|
(6 items) |
|
(1 item) |
|
(2 items) |
|
(5 items) |
|
(5 items) |
|
(7 items) |
|
(3 items) |
|
(7 items) |
|
(16 items) |
|
(10 items) |
|
(27 items) |
|
(15 items) |
|
(15 items) |
|
(13 items) |
|
(16 items) |
|
(15 items) |
When working with collection-like data sources in WPF, you can read properties of the selected item by writing your binding expressions as though there were only one source object. Here’s an example:
<DockPanel DataContext="{x:Static Fonts.SystemFontFamilies}"> <TextBlock DockPanel.Dock="Top" Text="{Binding Baseline}" /> <ListBox ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" /> </DockPanel>
The data source here is a collection – an array of FontFamily
objects. The ListBox
displays all of the items in this array. However, the TextBlock
has a binding expression that seems to make no sense – it tries to read the Baseline
property, and yet the source, an array, has no such property. When WPF encounters a binding to a non-existent property on a collection, WPF has a fallback strategy: it looks for the named property on the current item. Consequently, the TextBlock
shows the Baseline
property of the currently selected font.
This is jolly useful, but what do you do in situations where fallback doesn’t occur? For example, suppose you want to bind to the whole of the current item. Usually, a {Binding}
with no path has that effect:
<TextBlock DockPanel.Dock="Top" FontFamily="{Binding}" Text="The quick brown fox jumps over the lazy dog." />
However, this doesn’t work here. WPF’s alternate behaviour only kicked in for the {Binding Baseline}
example because arrays don’t have Baseline
properties. Conversely, {Binding}
is perfectly valid for an array, so WPF sees no need to fall back to an alternative interpretation. Unfortunately, this ends up trying to set the FontFamily
to an array of fonts, which fails. (This failure doesn’t trigger the fallback behaviour. That happens only if the binding cannot be evaluated. A binding that evaluates to an unsuitable type is insufficient.)
So how do we indicate that we want the current item, rather than the whole collection? Here’s how:
<TextBlock DockPanel.Dock="Top" FontFamily="{Binding /}" Text="The quick brown fox jumps over the lazy dog." />
In case the difference isn’t leaping out at you, there’s an extra “/” in the binding expression.
This struck me as less than totally obvious. (Hence this blog.) Indeed, I wasn’t even confident this would work first time I tried it. However, it makes some sense after a bit of thought. The main thing is to understand how this relates to a more common syntax:
Property="{Binding Items/Name}"
This binding expression means: the Items
property of the source is a collection; get the currently selected item in that collection, and read the Name
property.
In general, leaving out a property name in a binding path indicates that you want the whole object rather than a specific property. For example:
Property="{Binding Items/}"
This means: the Items
property of the source is a collection; return the current item from that collection. Likewise:
Property="{Binding /Name}"
This means: the source is a collection; get its current item and then return that item’s Name
property. Indeed, this last form is arguably what we should have used earlier. The expression {Binding /Baseline}
would indicate explicitly that we want the Baseline
of the current object, whereas {Binding Baseline}
relies on WPF having to guess that this was what we meant. One could argue that we should always use this form for this purpose, except the syntax looks misleadingly like some sort of file path or URL.
Having understood the two variants where we leave out one or other property name, it’s relatively straightforward to interpret the form with no name on either side.
Property="{Binding /}"
This means: the source is a collection; return the currently selected item in that collection. Or more succinctly: bind to the currently selected item.