Search code examples
c#wpftabcontrolcontentpresenter

How to fill ContentPresenter by binding


I've a problem to connect.

I started to connect my tabs with a tabcontrol.ressources and it worked to show the text of each tabs. Then I wanted to had a scroll for my TabItems and it doesn't work, nothing shows in tab... I can't even use tabcontrol.ressources anymore...

<DockPanel>
    <Button Background="DarkGoldenrod" Height="Auto" Command="{Binding OpenFlyoutDataCommand}">
        <StackPanel>
            <materialDesign:PackIcon Kind="ArrowRightBoldCircleOutline" Width="30" Height="30"/>
        </StackPanel>
    </Button>
    <TabControl ItemsSource="{Binding TabEDCWaferData, Mode=TwoWay}" 
                SelectedItem="{Binding SelectedTabEDCWaferData}">

        <!-- Used to create a scroolbar for tabitems -->

        <TabControl.Template>
            <ControlTemplate TargetType="TabControl">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition />
                    </Grid.RowDefinitions>
                    <ScrollViewer HorizontalScrollBarVisibility="Auto"  VerticalScrollBarVisibility="Hidden" >
                        <TabPanel Grid.Column="0" Grid.Row="0"
                                  Margin="2,2,2,0" IsItemsHost="true"/>
                    </ScrollViewer>
                    <ContentPresenter ContentSource="..."/>
                </Grid>
            </ControlTemplate>
        </TabControl.Template>

        <!-- Contains the text in the tab item ! -->

        <TabControl.Resources>
            <DataTemplate DataType="TabItem">
                <DockPanel>
                    <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabItem}}, Path=Content}" />
                </DockPanel>
            </DataTemplate>
        </TabControl.Resources>

    </TabControl>
</DockPanel>

This is connected to a collection of TabItem, where I've a function to add Items binding to an other button.

    private ObservableCollection<TabItem> _TabEDCWaferData;
    public ObservableCollection<TabItem> TabEDCWaferData
    {
        get { return _TabEDCWaferData; }
        set
        {
            _TabEDCWaferData = value;
            RaisePropertyChanged("TabEDCWaferData");
        }
    }

    public void AddTabItem(string name)
    {
        TabItem tab = new TabItem();
        tab.Header = name;
        tab.Content = "Temporary content";
        TabEDCWaferData.Add(tab);
    }

I read that I have to use the ContentPresenter, but I don't know how to bind it. I think this is not working with TabItems... I just want to bind it as I did in the Ressources by using the ContentPresenter.

I hope that I'm clear enough ! Thanks

EDIT : I try to display in the ContentPresenter the selected item tab content that I add in the function `AddTabItem.


Solution

  • With ContentPresenter, most times, this does the job:

     <ContentPresenter />
    

    The default ContentSource is "Content". That means it'll look at the Content property of the templated parent and it'll take whatever it finds there for its own content.

    But that doesn't help you at all, and you don't have to use ContentPresenter; it's just a convenience. In this case, the content you want to present is SelectedItem.Content, which isn't a valid ContentSource for ContentPresenter. But you can do the same thing with a binding on a ContentControl instead:

    <TabControl.Template>
        <ControlTemplate TargetType="TabControl">
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition />
                </Grid.RowDefinitions>
                <ScrollViewer 
                    Grid.Row="0"
                    HorizontalScrollBarVisibility="Auto"  
                    VerticalScrollBarVisibility="Hidden" 
                    >
                    <TabPanel 
                        Grid.Column="0" 
                        Margin="2,2,2,0" IsItemsHost="true"/>
                </ScrollViewer>
                <ContentControl
                    Grid.Row="1"
                    Content="{Binding SelectedItem.Content, RelativeSource={RelativeSource TemplatedParent}}"
                    />
            </Grid>
        </ControlTemplate>
    </TabControl.Template>
    

    TemplateBinding isn't going to work with a Path such as "SelectedItem.Content"; it only accepts names of properties on the templated parent. I fixed your Grid.Row attributes, too.

    Also, you may as well delete that DataTemplate for TabItem that you put in TabControl.Resources. That's not what DataTemplate is for; you use DataTemplates to define visual presentations for your viewmodel classes, but TabItem is a control. It already knows how to display itself, and in fact that DataTemplate is being ignored, so it's best not to leave it there; you'll only waste time later on making changes to it and trying to figure out why it's not having any effect. Your TabItems will display correctly without it.