0

I'm trying to bind the Text of a TextBox inside a TabItem to the header of that TabItem, so that both the header and the TextBox have the same content (f.e. when the header is "test" the TextBox should also show "test").

The TextBox is part of a DataTemplate, which I use as a StaticResource for ContentTemplate. The DataTemplate works fine, everything is shown as expected inside the tab. Only the TextBox is empty. I tried a lot of ways to define the RelativeSource, but none has worked so far.

<DataTemplate x:Key="myTemplate">
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="*"/>
            </Grid.ColumnDefinitions>
            <Image Grid.Column="0" Source="..."/>
            <Border BorderBrush="Black" BorderThickness="0 0 0.2 0"/>
            <StackPanel Grid.Column="1">
                <Grid>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="50"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="20"/>
                        <ColumnDefinition Width="*"/>
                    </Grid.ColumnDefinitions>
                    
                    <Label Grid.Column="0" Content="Name: "/>

                    <TextBox Grid.Column="1" Text="{Binding DataContext.Header, 
                     RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type TabItem}}}"/>

                    <Button Grid.Column="3" Content="Speichern"/>            
                </Grid>
            </StackPanel>
        </Grid>
    </DataTemplate> 

EDIT: I then use the template like that:

<TabControl>
                <TabItem ContentTemplate="{StaticResource myTemplate}" Header="Test"/>
                <TabItem Header="Tab 2"/>
                <TabItem Header="Tab 3"/>
</TabControl>
Christoph
  • 11
  • 3
  • Do you need a property of the Data Context or the TabItem itself? If the latter, correct `Text ="{Binding Header, RelativeSource={RelativeSource FindAncestor, AncestorType ={x:Type TabItem}}}"`. – EldHasp Jun 04 '21 at 15:14
  • To be clear, do you want the text entered in the textbox to show on the header or vice versa? In the first case bind `Header` property to `Text` property of the textbox as a oneway binding with update trigger on changed. In the second case, you do the exact opposite of above. – rufw91 Jun 05 '21 at 08:39
  • @EldHasp I tried that one too, doesn't work unfortunately – Christoph Jun 05 '21 at 16:21
  • @Rufw91 I want the second case. Can you give me an example code for that? I'm still kinda new to wpf – Christoph Jun 05 '21 at 16:22
  • I looked at the Dynamic Visual Tree - you were right. The titles and content of the tabs are in different branches. Different panels are used for their collections. All that there is in common between the presentation of the header and the content is only the Data Context. Therefore, the simplest solution is to add a property to the Data Context to which both the title and the TextBox will be bound. – EldHasp Jun 05 '21 at 18:20
  • It is not visible from your code for what type you created the template. Add details to your question: the type of the element, how you create a collection with them, how you bind it to the TabControl source. Then it will be easier for us to answer your question. – EldHasp Jun 05 '21 at 18:27
  • @EldHasp I eddited my question. I'm not quite sure how to work with DataContext. How would I add another property for the binding? – Christoph Jun 07 '21 at 10:53

1 Answers1

0

@EldHasp Я отредактировал свой вопрос. Я не совсем понимаю, как работать с DataContext. Как добавить другое свойство для привязки?

A data template is usually created for some specific data type.
In the ContentControl (including the TabItem), data goes to the Content property (often from the DataContext property) and the template in the ContentTemplate specifies its rendering.

Here is an example of a data type with one string property.
The example uses the BaseInpc class.

using Simplified;

namespace TabItemHeaderBinding
{
    public class TabItemContent : BaseInpc
    {
        private string _title;

        public string Title { get => _title; set =>Set(ref _title, value); }
    }
}

Typical for WPF is the implementation of the MVVM pattern.
In this case, you would receive a collection of elements <TabControl ItemsSource =" {Binding CollectionProperty} "...> into the TabControl source.
TabControl, in this case, would automatically create a TabItem for each item to which in the DataContext and in the Content it would pass the corresponding collection item.
And bindings in the element's template, in the header, etc. would have to be specified relative to this element.

You don't have MVVM, so I'm showing a simple example with minimal changes to your initial code.

<Window x:Class="TabItemHeaderBinding.ThbWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TabItemHeaderBinding"
        mc:Ignorable="d"
        Title="ThbWindow" Height="450" Width="800">
    <FrameworkElement.Resources>
        <DataTemplate x:Key="myTemplate" DataType="{x:Type local:TabItemContent}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Image Grid.Column="0" Source="/Febr20y;component/Image/block.png"/>
                <Border BorderBrush="Black" BorderThickness="0 0 0.2 0"/>
                <StackPanel Grid.Column="1">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="50"/>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="20"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>

                        <Label Grid.Column="0" Content="Name: "/>

                        <TextBox Grid.Column="1" Text="{Binding Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

                        <Button Grid.Column="3" Content="Speichern"/>
                    </Grid>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </FrameworkElement.Resources>
    <Grid>
        <TabControl>
            <TabItem ContentTemplate="{StaticResource myTemplate}"
                     Header="{Binding Title}"
                     Content="{Binding}">
                <TabItem.DataContext>
                    <local:TabItemContent Title="TitleTest"/>
                </TabItem.DataContext>
            </TabItem>
            <TabItem Header="Tab 2"/>
            <TabItem Header="Tab 3"/>
        </TabControl>
    </Grid>
</Window>

Работает отлично

Example MVVM implementation:

namespace TabItemHeaderBinding
{
    public class TabItemImageContent : TabItemContent
    {
        private object _imageSource;

        public object ImageSource { get => _imageSource; set =>Set(ref _imageSource, value); }
    }
}
using System.Collections.ObjectModel;

namespace TabItemHeaderBinding
{
    public class TabItemContentViewModel
    {
        public ObservableCollection<TabItemImageContent> Tabs { get; }
            = new ObservableCollection<TabItemImageContent>()
            {
                new TabItemImageContent() {Title = "First", ImageSource="/Febr20y;component/Image/block.png"},
                new TabItemImageContent() {Title = "Second", ImageSource="/Febr20y;component/Image/RAnimated1.gif"},
                new TabItemImageContent() {Title = "Third", ImageSource="/Febr20y;component/Image/plus.jpg"},
            };
    }
}
<Window x:Class="TabItemHeaderBinding.ThbMvvmWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:TabItemHeaderBinding"
        mc:Ignorable="d"
        Title="ThbMvvmWindow" Height="450" Width="800">
    <FrameworkElement.Resources>
        <DataTemplate x:Key="myTemplate" DataType="{x:Type local:TabItemImageContent}">
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Image Grid.Column="0" Source="{Binding ImageSource}"/>
                <Border BorderBrush="Black" BorderThickness="0 0 0.2 0"/>
                <StackPanel Grid.Column="1">
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="50"/>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="20"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>

                        <Label Grid.Column="0" Content="Name: "/>

                        <TextBox Grid.Column="1" Text="{Binding Title, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

                        <Button Grid.Column="3" Content="Speichern"/>
                    </Grid>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </FrameworkElement.Resources>
    <FrameworkElement.DataContext>
        <local:TabItemContentViewModel/>
    </FrameworkElement.DataContext>
    <Grid>
        <TabControl ItemsSource="{Binding Tabs}"
                    ContentTemplate="{DynamicResource myTemplate}">
            <TabControl.ItemContainerStyle>
                <Style TargetType="TabItem">
                    <Setter Property="Header" Value="{Binding Title}"/>
                </Style>
            </TabControl.ItemContainerStyle>
        </TabControl>
    </Grid>
</Window>
EldHasp
  • 6,079
  • 2
  • 9
  • 24