Question

I just started working with WPF and I'm trying to wrap my head around the XAML Bindings. After a lot of reading I thought I had an easy enough usecase to test my knowledge. But nada :-( I can't figure it out.

What I'm trying to do is the following: I have Address-Objects:

public IEnumerable<Address> Addresses
{
    get
    {
        if (addresses == null)
        {
            addresses = new Repository<Address>().GetAll().ToList<Address>();
        }
        return addresses;
    }
}

which have Rental-Objects e.g.

address.Rentals

also as IList. On my MainWidow I want to have 2 UserControls, one for the address and one for the rental information. If I click the Navigator on the address user control, I only want to see the rental records of the current address.

MainWindow

<Window x:Class="Swopt.Mira.WPFApp.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
            xmlns:local="clr-namespace:Swopt.Mira.WPFApp"
            Title="MainWindow" Height="500" Width="525">
<Window.Resources>
    <sampleData:DataContext x:Key="testDataContext" />
</Window.Resources>
<Grid x:Name="rootGrid" Background="White" DataContext="{StaticResource testDataContext}">
    <StackPanel>
        <local:RentalCustomer x:Name="rentalCustomer" Height="100"  />
        <local:Rentals Height="100" />
    </StackPanel>
</Grid>

Address

<UserControl
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" x:Class="Swopt.Mira.WPFApp.RentalCustomer" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300"
         x:Name="RentalCustomerUserControl">
<Grid x:Name="rootGrid" Background="White">
    <Grid.RowDefinitions>
        <RowDefinition Height="30" />
        <RowDefinition Height="30" />
    </Grid.RowDefinitions>
    <StackPanel>
        <TextBlock Text="Firma1"/>
        <TextBox x:Name="Firma1" Text="{Binding ElementName=collectionNavigator, Path=CurrentItem.Firma1}" />
    </StackPanel>
    <telerik:RadCollectionNavigator Grid.Row="1"
                                    Height="30"
                                    Margin="2"
                                    Grid.ColumnSpan="2"
                                    x:Name="collectionNavigator"
                                    Source="{Binding Addresses}"
                                    />
</Grid>

Rentals

<UserControl
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation" x:Class="Swopt.Mira.WPFApp.Rentals" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300"
         x:Name="RentalsUserControl">
<Grid x:Name="rootGrid" Background="White" >
    <StackPanel>
        <TextBlock Text="VertragsNr"/>
        <TextBox x:Name="VertragsNr" Text="{Binding ElementName=collectionNavigator2, Path=CurrentItem.VertragsNr}" />
    </StackPanel>
    <telerik:RadCollectionNavigator Grid.Row="1"
                                    Height="30"
                                    Margin="2"
                                    x:Name="collectionNavigator2"
                                    Source="{Binding Rentals}" />
</Grid>

Essentially what I want to do is Bind the DataContext of UserControl2 (Rentals) to the CurrentItem of collectionNavigator in UserControl1 (Addresses)

But I can't figure out how. I tried many things, with Binding Path and RelativeSource but none seem to work. the only way I could get it to work was to copy the content of UserControl1 into my MainWindow.xaml, but then I can't reuse it.

Any help is much appreciated.

UPDATE >>>>>

Working solution from Sheridan.

MainWindows

...
<local:RentalCustomer x:Name="rentalCustomer" Height="400"  />
<local:Rentals Height="100" DataContext="{Binding CurrentAddress, ElementName=rentalCustomer}" />

RentalCustomer.xaml

...
<telerik:RadCollectionNavigator Grid.Row="1"
                                    Height="30"
                                    Margin="2"
                                    Grid.ColumnSpan="2"
                                    x:Name="collectionNavigator"
                                    Source="{Binding Addresses}"
                                    CurrentItem="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=CurrentAddress, Mode=OneWayToSource}"
                                    />

RentalCustomer.xaml.cs

public Address CurrentAddress
    {
        get { return (Address)GetValue(CurrentAddressProperty); }
        set { SetValue(CurrentAddressProperty, value); }
    }

    // Using a DependencyProperty as the backing store for CurrentAddress.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty CurrentAddressProperty =
        DependencyProperty.Register("CurrentAddress", typeof(Address), typeof(RentalCustomer), new PropertyMetadata(null));
Was it helpful?

Solution

You can data bind the current item of a collection using the "/" Binding notation. Try something like this:

<UserControl Name="Control1" DataContext="{Binding SomeCollection}" />

<UserControl Name="Control2" DataContext="{Binding SomeCollection/}" />

Binding SomeCollection/ means bind to the current item of the SomeCollection collection. To make this work, you may need to set the Selector.IsSynchronizedWithCurrentItem Property to True on any container controls that you are selecting the current item in:

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

UPDATE >>>

Without an IsSynchronizedWithCurrentItem property, the "/" Binding notation won't work. Instead, you could expose the selected item from the collection as a DependencyProperty on the relevant UserControl. Then you could do something like this:

<UserControl Name="Control2" DataContext="{Binding SelectedItem, ElementName=Control1}" />

OTHER TIPS

You could provide the Rentals from your viewModel by binding the CurrentItem to your viewModel and expose the Rentals like this:

<telerik:RadCollectionNavigator CurrentItem={Binding CurrentItem} />

public Address CurrentItem
    {
       get; set;
    }

public IEnumerable<Rentals> Rentals
{
   get { return CurrentItem.Rentals; }

} 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top