【问题标题】:How to change appearance of TabItems in a scrolling WPF TabControl?如何在滚动的 WPF TabControl 中更改 TabItems 的外观?
【发布时间】:2011-04-08 23:34:28
【问题描述】:

我有一个滚动 TabControl,使用 ScrollViewer 和 StackPanel(StackPanel 设置为 IsItemsHost="true")。首先,我正在使用此处最初概述的解决方案 - Creating Scrolling Tabs Using WPF's TabControl 。目前它已经断开了链接(编辑:我在这里的一个论坛中找到了他的一个代码实例 - How to prevent TabControl from doing multi rows?),所以这里是 TabControl 的 xaml(不需要任何进一步的代码):

<TabControl x:Name="TabControl2" Height="Auto" TabStripPlacement="Bottom" VerticalAlignment="Bottom" Template="{DynamicResource TabControlControlTemplate1}" IsSynchronizedWithCurrentItem="True">
  <TabControl.Resources>
    <Style x:Key="TabScrollerRepeatButtonStyle" TargetType="{x:Type RepeatButton}">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate>
            <Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1" Margin="1,0">
              <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Content="{TemplateBinding ContentControl.Content}"/>
            </Border>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>

    <ControlTemplate x:Key="TabControlControlTemplate1" TargetType="{x:Type TabControl}">
      <Grid x:Name="Grid" KeyboardNavigation.TabNavigation="Local">
        <Grid.ColumnDefinitions>
          <ColumnDefinition x:Name="ColumnDefinition0"/>
          <ColumnDefinition x:Name="ColumnDefinition1" Width="0"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition x:Name="RowDefinition0" Height="Auto"/>
          <RowDefinition x:Name="RowDefinition1" Height="*"/>
        </Grid.RowDefinitions>
        <Border Grid.Row="1" Grid.Column="0" x:Name="ContentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0,0,1,1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local" KeyboardNavigation.DirectionalNavigation="Contained">
          <Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
            <Border Background="{TemplateBinding Background}" x:Name="Border1">
              <ContentPresenter DataContext="{x:Null}" Margin="{TemplateBinding Padding}" x:Name="PART_SelectedContentHost" Content="{TemplateBinding SelectedContent}" ContentTemplate="{TemplateBinding SelectedContentTemplate}" ContentTemplateSelector="{TemplateBinding SelectedContentTemplateSelector}" ContentSource="SelectedContent"/>
            </Border>
          </Border>
        </Border>
        <ScrollViewer x:Name="HeaderPanel" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,0,0,0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Disabled">
          <ScrollViewer.Style>
            <Style TargetType="{x:Type ScrollViewer}">
              <Setter Property="Template">
                <Setter.Value>
                  <ControlTemplate>
                    <Grid Margin="0,0,0,0" Grid.Row="0" Grid.Column="0" x:Name="HeaderPanel">
                      <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="20"/>
                        <ColumnDefinition Width="20"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="20"/>
                      </Grid.ColumnDefinitions>
                      <Grid.RowDefinitions>
                        <RowDefinition Height="Auto"/>
                      </Grid.RowDefinitions>
                      <RepeatButton Grid.Column="1" Content="&lt;" Command="ScrollBar.LineLeftCommand" Style="{DynamicResource TabScrollerRepeatButtonStyle}" Visibility="{Binding Path=ComputedHorizontalScrollBarVisibility, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/>
                      <ScrollContentPresenter Grid.Column="2" Content="{TemplateBinding ScrollViewer.Content}" />
                      <RepeatButton Grid.Column="3" Content="&gt;" Command="ScrollBar.LineRightCommand" Style="{DynamicResource TabScrollerRepeatButtonStyle}" Visibility="{Binding Path=ComputedHorizontalScrollBarVisibility, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"/>
                    </Grid>
                  </ControlTemplate>
                </Setter.Value>
              </Setter>
            </Style>
          </ScrollViewer.Style>
          <StackPanel IsItemsHost="true" Orientation="Horizontal" Background="{x:Null}" KeyboardNavigation.TabIndex="1"/>
        </ScrollViewer>
      </Grid>
    </ControlTemplate>
  </TabControl.Resources>
  <TabItem x:Name="TabItem1" Header="TabItem1"/>
  <TabItem x:Name="TabItem2" Header="TabItem2"/>
</TabControl>

如何调整每个 TabItem 的外观?例如,我想在 StackPanel 的帮助下在每个 TabItem 中放置一个 TextBox 和 TextBlock,这样我就可以拥有可重命名的选项卡(根据需要折叠一个或另一个)。我可能还想在每个选项卡上添加一个关闭按钮。通常,我会使用类似以下的内容:

                <TabControl.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Name="panel" Orientation="Horizontal">
                            <TextBox   Name="editHeader" Text="{Binding Header}" MaxWidth="250"/>
                            <TextBlock Name="textHeader" Text="{Binding Header}" />
                        </StackPanel>
                    </DataTemplate>
                </TabControl.ItemTemplate>

.. 但这根本没有效果。任何想法,将不胜感激。谢谢。

编辑:我仍在努力解决这个问题。该解决方案是否可能涉及 ContentPresenter 和/或 SelectedContentTemplate?

编辑 2:(这不会为我的问题增加价值)我真的,真的希望 WPF 包含这种开箱即用的东西。我对 TabControl 的默认行为感到困惑,而且几年后没有可滚动的 TabControl(也没有简单的解决方案)。

【问题讨论】:

    标签: c# wpf xaml tabcontrol itemtemplate


    【解决方案1】:

    我想我已经明白了(尽管仍然有点交叉——我还没有处理 TextBlock 与 TextBox 的可见性以进行重命名)。

    这与 Val 的解决方案相似,因为我在 TabControl.Resources 中对其 TabItem 工作,但相关的属性是 HeaderTemplate,我只是覆盖 DataTemplate 中的 ContentPresenter。 (避免替换\破坏 TabControl 免费提供的许多良好行为的措施)

    <TabControl.Resources>
        <Style TargetType="{x:Type TabItem}">
            <Setter Property="HeaderTemplate">
                <Setter.Value>
                    <DataTemplate>
                        <ContentPresenter>
                            <ContentPresenter.Content>
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock Text="{TemplateBinding Content}"/>
                                    <TextBox Text="{TemplateBinding Content}"/>
                                </StackPanel>
                            </ContentPresenter.Content>
                        </ContentPresenter>
                    </DataTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </TabControl.Resources>
    

    我有点像 WPF 新手,所以这基本上是我在谷歌上搜索到的东西不断试验的结果。对于那些感兴趣的人,这个链接(在 StackOverflow 上)最终对我帮助最大 - WPF TabItem Header Styling

    【讨论】:

      【解决方案2】:

      只是一个想法,

      您是否尝试过将文本块添加到 TabItem.Header?如果您这样做而不是模板,它可能会起作用。过去对我有影响

      【讨论】:

      • 这是一个想法,我之前玩过这个。如果不总是在适当的时间明确设置 TextBox 和 TextBlock 文本,我找不到一种方法。但如果有一种方法可以使用这个想法而不必这样做,我会非常感兴趣。 (例如,通过某种方式在 xaml 中执行此操作,并绑定到一个值)
      • 标签后面有可以绑定的对象吗?例如,字符串列表或其他东西?因为如果您在使用 header 属性时尝试绑定到 header,它会填满。顺便说一句,有一种方法可以在同级元素之间使用绑定。只需命名元素(例如,Name = "MyControl",然后您可以使用Binding ElementName=MyControl, Path=PropertyToBindTo 绑定到它。如果失败,您可以使用Binding RelativeSource={RelativeSource, Mode=FindAncestor, AncestorType=TypeOfParentYouWantToBindTo}
      • 谢谢。关于兄弟姐妹之间绑定的信息可能会派上用场来处理可见性。目前,我在 TabItem 的 ContentPresenter 中有一个不可见的 ToggleButton(我对这个问题的解决方案的修改),并且我正在使用您的提示将可见性绑定到其 IsChecked 属性。我不确定我是否能够从我的代码中访问它,但值得一试。
      • 取决于您希望文本框如何变得可编辑。您可以只使用 DataTriggers,因此当您选择选项卡时,标题变为可编辑,只需使用绑定到 IsSelected 属性(或选项卡模板中的任何内容)的数据触发器。如果您愿意,我愿意就这个主题与您联系,因为如果您在 UI 中添加了那么多逻辑,那么视图模型可能就是这里的方法:)
      • 我已经移除了不可见的切换按钮,并且现在设置了我的 TabControl 的 ItemsSource 以绑定到对象列表。这些对象包含一个额外的值,反映是否正在发生编辑,我现在将可见性绑定到它。我对视图模型完全不熟悉。对应可能是个好主意:)
      【解决方案3】:

      嘿,猜猜看。我做过类似的事情,不过我的基础是这个系列

      http://www.blogs.intuidev.com/post/2010/post/2010/01/25/TabControlStyling_PartOne.aspx

      使用的方法是简单地设置 tabitems 模板的样式。例如:

      <TabControl.Resources>
          <Style TargetType="{x:Type TabItem}">
              <Setter Property="Template">
                  <Setter.Value>
                      <ControlTemplate TargetType="{x:Type TabItem}">
                      <!-- your custom template goes here -->
      
                      </ControlTemplate>
                  </Setter.Value>
              </Setter>
          </Style>
      </TabControl.Resources>
      

      不幸的是,这种方法意味着您必须完全重新定义选项卡项的外观和行为方式。但是提供的链接给出了如何实现这一点的很好的例子。

      希望对你有帮助。

      【讨论】:

      • 我还没有让 TabItems 绑定到 Header(使用 Text="{Binding Header}" - 无论出于何种原因它都不起作用),但它对样式有明显的影响TabItems,所以这可能是一个有前途的角度。知道为什么绑定到标题会失败吗?
      • 我现在明白你的意思,当你说我必须重新定义 tabitems 的外观时(即,当我只放一个 TextBlock 时,我只得到一个 TextBlock 而没有包含框)。如果可能的话,我希望避免写这些和行为改变。
      • 不确定绑定失败的原因,但尝试将绑定添加到模板设置器上方的设置器。 " 看看这是否可行。可能有更好的方法,但至少现在你有一个后备;)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-29
      • 2011-02-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多