2

I am having trouble accessing the correct DataContext for TabItems with a dynamically populated TabControl.

Using the below code i bind the ItemsSource of my TabControl to an ObservableCollection<TabViewModel> on my MainViewModel.

Based on the Type property of the each TabViewModel in the ItemSource, a different UserControl is selected as the Content property of the TabItem. It is here where this start to go wrong

These UserControls need to have their DataContext set to the MainViewModel, however accessing this is not possible as the dynamic TabItems seem to be created in a different visual tree.

<TabControl x:Name="mainTabControl" ItemsSource="{Binding TabList}">
    <TabControl.ItemContainerStyle>
        <Style TargetType="TabItem">
            <Setter Property="Header" Value="{Binding Name}" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=Type}" Value="Summary" >
                    <Setter Property="Content">
                        <Setter.Value>
                            <views:AnalysisArisingSummaryControl />
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=Type}" Value="User Defined" >
                    <Setter Property="Content">
                        <Setter.Value>
                            <views:AnalysisUserDefinedControl />
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=Type}" Value="System Defined" >
                    <Setter Property="Content">
                        <Setter.Value>
                            <views:AnalysisSystemDefinedControl />
                        </Setter.Value>
                    </Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TabControl.ItemContainerStyle>           
</TabControl>

Any ideas as to how to accomplish this. I dont really want to have to reference data between ViewModels if i can help it.

Sheridan
  • 68,826
  • 24
  • 143
  • 183
DAVEWASLIN
  • 159
  • 21
  • This question/situation is worded poorly. If you want all of the tabs to show the `MainViewModel`, why would you create dynamic tabs? Why not just have `TabItems` defined in a XAML `TabControl` that all show `MainViewModel`? If you wanted to reference the different classes within `MainViewModel` to pull the different tab names/classes, why even do it that way? Why not just pull the appropriate class and set it directly? What's with all the triggers and binding? – vapcguy Oct 14 '16 at 17:02

1 Answers1

1

You are approaching this whole scenario wrong. A far better solution would be to first declare a base class for your different view model classes. Then each of your different view models should extend that base class. This will enable you to have one collection of the type of that base class, which you can add all of your different view models into.

The next step would be to declare a DataTemplate for each of your view model types to determine how they should be displayed. It is important that you do not set the x:Key value on these DataTemplates so that they will be applied to your items implicitly. In this case, you will have no need to use Triggers to differentiate between the different view models and the Framework will just automatically render them according to the DataTemplates that you declared.

<DataTemplate DataType="{x:Type ViewModels:AnalysisArisingViewModel}">
    <Views:AnalysisArisingSummaryControl />
</DataTemplate>
...
<DataTemplate DataType="{x:Type ViewModels:AnalysisSystemDefinedViewModel}">
    <Views:AnalysisSystemDefinedControl />
</DataTemplate>

UPDATE >>>

In order to data bind to a property of a parent view model, you can use a RelativeSource Binding. So, if you have a collection property named Collection in a MainViewModel instance that is set as the DataContext of the MainWindow.xaml Window, then you could data bind to it from within your UserControls like this:

<DataGrid ItemsSource="{Binding DataContext.Collection, RelativeSource={RelativeSource 
    AncestorType={x:Type MainWindow}}}" ... />
Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • Thats great and its a much better approach, however it hasnt actually solved my problem. On each of the three data templates, i have DataGrids which i want to bind to observablecollections on the MainViewModel, however when i run my project, these controls are bound to the SummaryTabViewModel, UserDefinedTabViewModel, or SystemDefinedTabViewModel wich corresponds to their type. How exactly can i access the MainViewModel which houses these collections along with the TabList that the mainTabControl was bound to. – DAVEWASLIN Jun 12 '14 at 13:19