Skip Navigation LinksHome > View Post

Binding to the Current Item in WPF

In Reason 2. Databinding I directly bound the GroupBox's DataContext to the SelectedItem of the ListBox:

<GroupBox Header="Book Details" DataContext="{Binding ElementName=_lstBooks, Path=SelectedItem}">

But this approach wasn't necessary (in this case I wanted to avoid clouding the binding issue) because WPF's databinding has a few tricks up its sleeve when it comes to collections.

If a property (a DependencyProperty of course) is bound to a collection and specifies a Path that does not exist on that collection, the binding will fall back to trying the same Path on the current item in the collection.

In that case all we need to do is instruct the ListBox to synchronise the CurrentItem, like so:

<ListBox ItemsSource="{Binding}" ... IsSynchronizedWithCurrentItem="True" />

From now on, we don't need to bind directly to the listbox to find the selectedItem so we can remove the DataContext from the GroupBox above but our bindings in the textboxes can remain exactly as they are as they'll fallback to selecting the current item. To quote Montgomery Burns, "Excellent".

<TextBox ... Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />

Furthermore we can adjust the trigger we created in Reason 4. Triggers on the GroupBox to avoid coupling it to the ListBox. So we go from...

<DataTrigger Binding="{Binding ElementName=_lstBox, Path=SelectedIndex}" Value="-1">
    <Setter Property="GroupBox.IsEnabled" Value="False" />
</DataTrigger>

... to ...

<DataTrigger Binding="{Binding /}" Value="{x:Null}">
    <Setter Property="GroupBox.IsEnabled" Value="False" />
</DataTrigger>

You may be wondering what the weird '/' is for in the binding. We couldn't just use {Binding} here and specify no Path (the default property in a binding markup extension) as the binding wouldn't 'fallback' as we described above, it would just bind to the collection. No good, we want the current item.

Fortunately, there is this forward slash syntax which effectively takes the form <collection>/<current-item-property>.

So if my current DataContext had a property called Bananas which was a collection of Banana objects (which has a size property, of course) I could deep bind to the current banana like so: {Binding Bananas/Size}. Very clever.

In our original example the DataContext is itself a collection so we don't need to specify the collection and we want the whole current item, not a property thereof. So we can get away with just the '/'.

With this in mind, we'd be better to change the Binding in our TextBox to use a forward slash. Also, this will avoid the fallback and prevent the UI from breaking if I was to add a .Name property to my collection.

<TextBox ... Text="{Binding /Name, UpdateSourceTrigger=PropertyChanged}" />

I'll include these changes in the next example when Reason 6 is published. You should find the Add/Remove behaviour much more desirable now and all for free thanks to the power of synchronizing the current item.

Finally, a quick example to show this stuff off in pure Xaml.

<Page
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">

    <Page.Resources>
        <x:Array x:Key="myarray" Type="{x:Type sys:String}">
            <sys:String>Item 1</sys:String>
            <sys:String>Item 2</sys:String>
            <sys:String>Item 3</sys:String>
            <sys:String>Item 4</sys:String>
        </x:Array>
    </Page.Resources>
    <WrapPanel Orientation="Horizontal" DataContext="{Binding Source={StaticResource myarray}, Path=.}">
        <ListBox ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" Margin="5" />
        <TextBlock Text="{Binding /}" Margin="5" />
        <ComboBox ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" Margin="5" />
    </WrapPanel>

</Page>

As you can see, I create an Array of string directly in Xaml and embed them as a resource to the page. Then I have a ListBox with current item synchronization turned on followed by a TextBlock showing the current item. Finally, we have a ComboBox also bound to the array and with current item synchronization turned on.

example

Here's the xaml file for you to view.

Notice how the two ItemsControls (ListBox and ComboBox) are always synchronised.

Update - how this magic works was explained in a subsequent post How binding to the current item works.

Tags: WPF

 
Josh Post By Josh Twist
9:57 AM
29 Oct 2007

» Next Post: Binding to Attached Properties
« Previous Post: Reason 5. Styles

Comments are closed for this post.

Posted by NisanFlexan @ 10 Feb 2009 2:42 AM
Very very good and essential information regarding Binding and Path property.
Thanks a lot.

Posted by ASD @ 03 Nov 2011 7:41 AM
Thanks!

© 2005 - 2014 Josh Twist - All Rights Reserved.