0
votes

Okay, I got this Tabcontrol containing a ListBox. Now my problem it that I would like to bind <TextBox x:Name="DetailTextBox" Text="{Binding Detail}"/> to the selectedItem in the listbox and show the Detail property value. Note that the TextBox is not part of the TabControl, but is in another Column.

I can't quite figure out, how to handle binding, when there a multiple ListBox'es, one in each TabControl Item.

My classes

public class TabViewModel
{
    public string Name { get; set; }
    public ObservableCollection<TabItemViewModel> Collection { get; set; }
}

public class TabItemViewModel
{
    public string Title { get; set; }
    public string Detail { get; set; }
}

public MainWindow()

 var tabViewModels = new ObservableCollection<TabViewModel>();
            tabViewModels.Add(new TabViewModel{Name = "Tab 1", Collection = new ObservableCollection<TabItemViewModel>{new TabItemViewModel{Detail = "Detail 1.1", Title = "Title 1.1"}, new TabItemViewModel{Detail = "Detail 2.2", Title = "Title 2.2"}}});
            tabViewModels.Add(new TabViewModel { Name = "Tab 2", Collection = new ObservableCollection<TabItemViewModel> { new TabItemViewModel { Detail = "Detail 2.1", Title = "Title 2.1" }, new TabItemViewModel { Detail = "Detail 2.2", Title = "Title 2.2" } } });
            tabViewModels.Add(new TabViewModel { Name = "Tab 3", Collection = new ObservableCollection<TabItemViewModel> { new TabItemViewModel { Detail = "Detail 3.1", Title = "Title 3.1" }, new TabItemViewModel { Detail = "Detail 3.2", Title = "Title 3.2" } } });
            DataContext = tabViewModels;

MainWindow.xaml.

<Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="50*"/>
            <ColumnDefinition Width="50*"/>
        </Grid.ColumnDefinitions>
        <TabControl ItemsSource="{Binding}" Grid.Column="0" SelectedIndex="0">
            <TabControl.ItemContainerStyle>
                <Style TargetType="{x:Type TabItem}">
                    <Setter Property="Header">
                        <Setter.Value>
                            <Binding Path="Name"/>
                        </Setter.Value>
                    </Setter>
                </Style>
            </TabControl.ItemContainerStyle>
            <TabControl.ContentTemplate>
                <DataTemplate>
                    <ListBox ItemsSource="{Binding Collection}">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <Label Content="{Binding Title}" />
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </DataTemplate>
            </TabControl.ContentTemplate>
        </TabControl>
        <StackPanel Grid.Column="1">
            <TextBox x:Name="DetailTextBox" Text="{Binding Detail}"/>
        </StackPanel>
    </Grid>

enter image description here

EDIT

Temp Solution Found a way to make it work, but I'm still looking for a pure Xaml solution. Added a SelectionChange event

 <ListBox ItemsSource="{Binding Collection}" SelectionChanged="ListBox_SelectionChanged">

     private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
                if (e.AddedItems.Count > 0)
                    DetailTextBox.DataContext = (TabItemViewModel) e.AddedItems[0];
            }
1
use a converter OR sync your View selections to your ViewModelsJake Berger
Can you direct me to some info about doing that?gulbaek
Both :-) I have never used a converter and I'm not sure what the sync solution is.gulbaek
sync: in your ViewModels; add another property which is the same as your collections; so in TabViewModel, add TabItemViewModel Selected. then in your View, bind ListBox SelectedItem to Selected. converterJake Berger

1 Answers

2
votes

How about this, I was surprised myself :-)
Make these changes to your Xaml.

<TabControl ItemsSource="{Binding}" 
    Grid.Column="0" SelectedIndex="0" 
    IsSynchronizedWithCurrentItem="True">

<ListBox ItemsSource="{Binding Collection}" 
    IsSynchronizedWithCurrentItem="True">

<TextBox x:Name="DetailTextBox" 
    Text="{Binding /Collection/Detail}"/>

The '/' binds to the currently selected item of a control's CollectionView.

So the binding above is drilling down through

  • The currently SelectedItem of the ObservableCollection set on the Data Context
  • The Collection property on that item
  • The currently SelectedItem of the Collection property (ObservableCollection)
  • The Detail property on that item.

In order for this to work we need to specify IsSynchronizedWithCurrentItem="True" to ensure the SelectedItem remains synchronized with the current item of each collection.