从 DataTemplate 中绑定到 TabItem 标头

Posted

技术标签:

【中文标题】从 DataTemplate 中绑定到 TabItem 标头【英文标题】:Binding to a TabItem Header from within DataTemplate 【发布时间】:2021-08-22 14:41:48 【问题描述】:

我正在尝试将 TabItem 内的 TextBox 的文本绑定到该 TabItem 的标题,以便标题和 TextBox 具有相同的内容(当标题为“测试" TextBox 也应该显示 "test")。

TextBoxDataTemplate 的一部分,我将其用作StaticResourceContentTemplateDataTemplate 工作正常,选项卡内的所有内容都按预期显示。只有TextBox 是空的。我尝试了很多方法来定义RelativeSource,但到目前为止都没有奏效。

<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> 

编辑: 然后我使用这样的模板:

<TabControl>
                <TabItem ContentTemplate="StaticResource myTemplate" Header="Test"/>
                <TabItem Header="Tab 2"/>
                <TabItem Header="Tab 3"/>
</TabControl>

【问题讨论】:

您需要数据上下文的属性还是 TabItem 本身的属性?如果是后者,请更正Text ="Binding Header, RelativeSource=RelativeSource FindAncestor, AncestorType =x:Type TabItem" 明确地说,您希望在文本框中输入的文本显示在标题上还是反之亦然?在第一种情况下,将Header 属性绑定到文本框的Text 属性,作为单向绑定,更新触发器已更改。在第二种情况下,您的操作与上述完全相反。 @EldHasp 我也试过了,可惜没用 @Rufw91 我想要第二种情况。你能给我一个示例代码吗?我对 wpf 还是有点陌生​​ 我查看了动态视觉树 - 你是对的。选项卡的标题和内容位于不同的分支中。不同的面板用于他们的收藏。标题的呈现和内容之间的所有共同点只是数据上下文。因此,最简单的解决方案是向 Data Context 添加一个属性,标题和 TextBox 都将绑定到该属性。 【参考方案1】:

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

通常为某些特定数据类型创建数据模板。 在 ContentControl(包括 TabItem)中,数据进入 Content 属性(通常来自 DataContext 属性),而 ContentTemplate 中的模板指定其呈现。

以下是具有一个字符串属性的数据类型示例。 该示例使用BaseInpc class。

using Simplified;

namespace TabItemHeaderBinding

    public class TabItemContent : BaseInpc
    
        private string _title;

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

典型的 WPF 是 MVVM 模式的实现。 在这种情况下,您将在 TabControl 源中收到一组元素 &lt;TabControl ItemsSource =" Binding CollectionProperty "...&gt;。 在这种情况下,TabControl 会自动为 DataContext 中的每个项目创建一个 TabItem,并且在 Content 中它会传递相应的集合项目。 并且必须相对于该元素指定元素模板、标题等中的绑定。

您没有 MVVM,所以我展示了一个简单的示例,对您的初始代码进行了最小的更改。

<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>

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

MVVM 实施示例:

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>

【讨论】:

我强烈推荐学习 MVVM。这样您就可以更轻松地实施许多解决方案。 我用一个示例 MVVM 实现补充了我的答案。你看看并研究它。对你很有帮助。 再次感谢,我会努力理解的:)

以上是关于从 DataTemplate 中绑定到 TabItem 标头的主要内容,如果未能解决你的问题,请参考以下文章

绑定到 DataTemplate 中的视图模型属性

如何向上发送数据?从Datatemplate到上面

ItemsControl 中 DataTemplate 中的 WPF UserControl - 如何绑定到 ItemsSource 的父级

如何将 ObservableCollection 绑定到 DataTemplate 中的文本框?

如何将 DataTemplate 数据类型绑定到接口?

使用动态项绑定到Listbox的DataTemplate中的控件DependencyProperty不起作用