1
votes

I am binding a collection of TabViewModel items to a TabControl. Each of these has a header string property, and a content property of my own custom type BaseTabContentViewModel, an abstract class which each actual tab data viewmodel implements. Eg ValuationTabViewModel which is a sub-class of BaseTabContentViewModel.

I add the new TabViewModel to the Observable<TabViewModel> for the TabControl to pick up and it shows in the UI. I have overridden style templates for the layout of the tab control and header which work fine. The only trouble is the content doesn't find the template in my resource dictionary based on its type, it just displays the full qualified class name of the viewmodel, showing that it is not finding a default template for this class.

Why isn't the ValuationTabViewModel that is being displayed, finding the datatemplate for this type below?

My main view model.

public ObservableCollection<TabViewModel> DetailTabs { get; }

var valuationTab = new TabViewModel(DetailTabConstants.ValuationTab, new ValuationTabViewModel(_eventAggregator, _errorNotifier, _windsorContainer));

DetailTabs = new ObservableCollection<TabViewModel> { valuationTab };

Main XAML

                            <TabControl Margin="0,-2,0,0" x:Name="SelectionTabs" Style="{StaticResource DetailTabControl}" ItemsSource="{Binding DetailTabs}" 
                                        SelectedValue="{Binding SelectedTab, Mode=TwoWay}" ItemContainerStyle="{StaticResource DetailTabItem}">
                                <TabControl.ItemTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding Header}" />
                                    </DataTemplate>
                                </TabControl.ItemTemplate>
                                <TabControl.ContentTemplate>
                                    <DataTemplate>
                                        <TextBlock Text="{Binding Content}" />
                                    </DataTemplate>
                                </TabControl.ContentTemplate>
                            </TabControl>

The content style template I want it to use

<DataTemplate x:Key="ValuationTabTemplate" DataType="{x:Type detailTabs1:ValuationTabViewModel}" >
        <detailTabs:ValuationTab Margin="0,10,0,10" />
    </DataTemplate>

And my Tab item ViewModel class

public class TabViewModel : ViewModelBase
{
    private string _header;
    private BaseTabContentViewModel _content;

public string Header
{
    get => _header;
    set
    {
        _header = value; 
        RaisePropertyChanged(nameof(Header));
    }
}

public BaseTabContentViewModel Content
{
    get => _content;
    set
    {
        _content = value;
        RaisePropertyChanged(nameof(Content));
    }
}

public TabViewModel(string header, BaseTabContentViewModel viewModel)
{
    Header = header;
    Content = viewModel;            
}
}
2

2 Answers

1
votes

Remove the <TabControl.ContentTemplate> element and define an implicit DataTemplate (without an x:Key) for each type:

<TabControl Margin="0,-2,0,0" x:Name="SelectionTabs" Style="{StaticResource DetailTabControl}" ItemsSource="{Binding DetailTabs}" 
            SelectedValue="{Binding SelectedTab, Mode=TwoWay}" ItemContainerStyle="{StaticResource DetailTabItem}">
    <TabControl.Resources>
        <DataTemplate DataType="{x:Type detailTabs1:ValuationTabViewModel}">
            <detailTabs:ValuationTab Margin="0,10,0,10" />
        </DataTemplate>
    </TabControl.Resources>
    <TabControl.ItemTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Header}" />
        </DataTemplate>
    </TabControl.ItemTemplate>
</TabControl>
0
votes

I think your custom DataTemplate isn't being used because you have specified both a Key and a DataType for it, and the Key takes precedence.

As per the Microsoft docs:

... if you assign this DataTemplate an x:Key value, you are overriding the implicit x:Key and the DataTemplate would not be applied automatically

I would suggest removing the Key property and just using DataType:

<DataTemplate DataType="{x:Type detailTabs1:ValuationTabViewModel}">
    ...
</DataTemplate>

Also, as @mm8 implied, you are explicitly setting the ContentTemplate of your TabControl. You need to remove that from the XAML.