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.
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 DataTemplate
s so that they will be applied to your items implicitly. In this case, you will have no need to use Trigger
s to differentiate between the different view models and the Framework will just automatically render them according to the DataTemplate
s 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 UserControl
s like this:
<DataGrid ItemsSource="{Binding DataContext.Collection, RelativeSource={RelativeSource
AncestorType={x:Type MainWindow}}}" ... />