WPF选项卡控件的样式设计

10

我有一个外观相当标准的 UI。它在左侧有一列图标,当单击时会在右侧打开不同的用户控件。目前我对选择图标和用户控件容器使用了不同的控件。我一直在尝试解决奇怪的焦点问题,现在想知道是否可以将 TabControl 的样式设置得与我的 UI 相似(以假设 TabControl 在导航选项卡时不会出现焦点问题)。

这是基本 UI 的屏幕截图。样式大部分是如何使选定的 TabControl 页面看起来像我的图标列。谁能提供一些建议,告诉我如何使用 TabControl 来实现这个效果? 我的 XAML 目前非常薄弱。

alt text http://img413.imageshack.us/img413/8399/directoru.png


2
或者我可能需要花费将近一周的时间才能找到时间添加一个示例。希望它有所帮助。 - Bryan Anderson
@CJBS,最初发布帖子并拥有该图像的是BrentRobi。我所说的示例在下面已接受答案的编辑中。 - Bryan Anderson
@BryanAnderson - 对不起 - 你是对的。我打了“@B”并接受了第一个条目而没有检查。 - CJBS
@BrettRobi Imageshack的图片已经失效了。有没有可能嵌入到其他地方? - CJBS
1
@CJBS 抱歉,我早已失去了那张图片的轨迹,甚至是它所属的应用程序。不过很高兴看到这仍然有关联性,七年后... - BrettRobi
2个回答

21
<TabControl TabStripPlacement="Left">
    ...
</TabControl>

然后您将图标放入TabItems的Header属性中,将UserControls放入Content属性中。这样可以完成一半的工作。如果您想要完全相同的外观,则需要通过复制当前模板(使用Blend或ShowMeTheTemplate来复制当前模板)并根据需要进行修改来重新设计TabControl和TabItem。但只是更改这些属性就足以让您测试TabControl是否可以消除焦点问题。

编辑:这里有一个示例模板,非常接近您的屏幕截图

<Style TargetType="{x:Type TabItem}">
    <Setter Property="Background" Value="Transparent" />

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabItem}">

                <Border x:Name="PART_Border" Background="{TemplateBinding Background}" BorderThickness="1" BorderBrush="LightGray" Margin="2">
                    <ContentPresenter ContentSource="Header" Margin="2" />
                </Border>

                <ControlTemplate.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter TargetName="PART_Border" Property="BorderBrush" Value="Black" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

<Style TargetType="{x:Type TabControl}">
    <Setter Property="TabStripPlacement" Value="Left" />
    <Setter Property="Margin" Value="2" />
    <Setter Property="Padding" Value="2"    />
    <Setter Property="Background" Value="White" />


    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabControl}">
                <Grid ClipToBounds="True" SnapsToDevicePixels="True" KeyboardNavigation.TabNavigation="Local">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Name="ColumnDefinition0" />
                        <ColumnDefinition Width="0" Name="ColumnDefinition1" />
                    </Grid.ColumnDefinitions>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" Name="RowDefinition0" />
                        <RowDefinition Height="*" Name="RowDefinition1" />
                    </Grid.RowDefinitions>

                    <Border x:Name="HeaderBorder" 
                            BorderBrush="Black" 
                            BorderThickness="1" 
                            CornerRadius="5" 
                            Background="#FAFAFA"
                            Margin="0,0,0,5">
                        <TabPanel IsItemsHost="True"
                                  Name="HeaderPanel" 
                                  Panel.ZIndex="1" 
                                  KeyboardNavigation.TabIndex="1"
                                  Grid.Column="0" 
                                  Grid.Row="0" 
                         />
                    </Border>

                    <Grid Name="ContentPanel" 
                          KeyboardNavigation.TabIndex="2" 
                          KeyboardNavigation.TabNavigation="Local" 
                          KeyboardNavigation.DirectionalNavigation="Contained" 
                          Grid.Column="0" 
                          Grid.Row="1">
                        <Border Background="{TemplateBinding Background}"
                                BorderBrush="{TemplateBinding BorderBrush}" 
                                BorderThickness="{TemplateBinding BorderThickness}"
                                CornerRadius="5">
                            <ContentPresenter Content="{TemplateBinding SelectedContent}" 
                                              ContentTemplate="{TemplateBinding SelectedContentTemplate}" 
                                              ContentStringFormat="{TemplateBinding SelectedContentStringFormat}" 
                                              ContentSource="SelectedContent" 
                                              Name="PART_SelectedContentHost" 
                                              Margin="2" 
                                              SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" 
                            />
                        </Border>
                    </Grid>
                </Grid>

                <ControlTemplate.Triggers>
                    <Trigger Property="TabControl.TabStripPlacement" Value="Bottom">
                        <Setter TargetName="HeaderPanel" Property="Grid.Row" Value="1" />
                        <Setter TargetName="ContentPanel" Property="Grid.Row" Value="0" />
                        <Setter TargetName="RowDefinition0" Property="RowDefinition.Height" Value="*" />
                        <Setter TargetName="RowDefinition1" Property="RowDefinition.Height" Value="Auto" />
                        <Setter TargetName="HeaderBorder" Property="FrameworkElement.Margin" Value="0,5,0,0" />
                    </Trigger>
                    <Trigger Property="TabControl.TabStripPlacement" Value="Left">
                        <Setter TargetName="HeaderPanel" Property="Grid.Row" Value="0" />
                        <Setter TargetName="ContentPanel" Property="Grid.Row" Value="0" />
                        <Setter TargetName="HeaderPanel" Property="Grid.Column" Value="0" />
                        <Setter TargetName="ContentPanel" Property="Grid.Column" Value="1" />
                        <Setter TargetName="ColumnDefinition0" Property="ColumnDefinition.Width" Value="Auto" />
                        <Setter TargetName="ColumnDefinition1" Property="ColumnDefinition.Width" Value="*" />
                        <Setter TargetName="RowDefinition0" Property="RowDefinition.Height" Value="*" />
                        <Setter TargetName="RowDefinition1" Property="RowDefinition.Height" Value="0" />
                        <Setter TargetName="HeaderBorder" Property="FrameworkElement.Margin" Value="0,0,5,0" />
                    </Trigger>
                    <Trigger Property="TabControl.TabStripPlacement" Value="Right">
                        <Setter TargetName="HeaderPanel" Property="Grid.Row" Value="0" />
                        <Setter TargetName="ContentPanel" Property="Grid.Row" Value="0" />
                        <Setter TargetName="HeaderPanel" Property="Grid.Column" Value="1" />
                        <Setter TargetName="ContentPanel" Property="Grid.Column" Value="0" />
                        <Setter TargetName="ColumnDefinition0" Property="ColumnDefinition.Width" Value="*" />
                        <Setter TargetName="ColumnDefinition1" Property="ColumnDefinition.Width" Value="Auto" />
                        <Setter TargetName="RowDefinition0" Property="RowDefinition.Height" Value="*" />
                        <Setter TargetName="RowDefinition1" Property="RowDefinition.Height" Value="0" />
                        <Setter TargetName="HeaderBorder" Property="FrameworkElement.Margin" Value="5,0,0,0" />
                    </Trigger>
                    <Trigger Property="UIElement.IsEnabled" Value="False">
                        <Setter Property="TextElement.Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

这基本上是普通的TabControl的副本,只是添加和删除了一些边框。希望能够帮助到您。


谢谢您的回复。我真正需要建议的是重新模板化。这是我认为可能会阻止这成为可行解决方案的部分。 - BrettRobi
我可以在几个小时后回家时提供一个例子。 - Bryan Anderson
Brett,我相信你会发现重新模板化并不那么糟糕。听起来很可怕,但一旦你开始做,就会觉得有点有趣。此外,拥有旧模板可以回退的意味着如果最坏的情况发生,你总是可以重新开始。 - Ed Gonzalez
谢谢你的示例,Bryan。我会在接下来的几天里仔细研究它。 - BrettRobi

2
如何使用 DockPanel 模板化 TabControl,并将 TabPanelDockPanel.Dock 属性与原始的 TabStripPlacement 属性绑定,如下所示?
<Style  TargetType="{x:Type TabControl}" >
    <Setter Property="OverridesDefaultStyle" Value="True" />
    <Setter Property="SnapsToDevicePixels" Value="True" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabControl}">
                <DockPanel KeyboardNavigation.TabNavigation="Local" LastChildFill="True">
                    <TabPanel DockPanel.Dock="{TemplateBinding TabStripPlacement}"
                        Name="HeaderPanel"
                        Grid.Row="0"
                        Panel.ZIndex="1" 
                        Margin="0,0,4,1" 
                        IsItemsHost="True"
                        KeyboardNavigation.TabIndex="1"
                        Background="Transparent" />
                    <Border 
                        Name="Border" 
                        Background="Transparent" 
                        BorderBrush="Black" 
                        BorderThickness="1" 
                        CornerRadius="2" >
                        <ContentPresenter 
                            ContentSource="SelectedContent" />
                    </Border>
                </DockPanel>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="False">
                        <Setter Property="Foreground" Value="Black" />
                        <Setter TargetName="Border" Property="BorderBrush" Value="DarkGray" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接