一、前言

程序中经常会用到TabControl控件,默认的控件样式很普通。而且样式或功能不一定符合我们的要求。比如:我们需要TabControl的标题能够居中、或平均分布;或者我们希望TabControl的标题能够进行关闭。要实现这些功能我们需要对TabControl的样式进行定义。

二、实现TabControl的标题平均分布

默认的TabControl标题是使用TabPanel容器包含的。要想实现TabControl标题头平均分布,需要把TabPanel替换成UniformGrid;

替换后的TabControl样式如下:


<Style x:Key="TabControlStyle" TargetType="{x:Type TabControl}">
<Setter Property="Padding" Value="2"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="#FFACACAC"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid x:Name="templateRoot" ClipToBounds="True" SnapsToDevicePixels="True" 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>
<UniformGrid x:Name="HeaderPanel" Rows="1" Background="Transparent" Grid.Column="0" IsItemsHost="True" Margin="0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
<Line X1="0" X2="{Binding ActualWidth, RelativeSource={RelativeSource Self}}" Stroke="White" StrokeThickness="0.1" VerticalAlignment="Bottom" Margin="0 0 0 1" SnapsToDevicePixels="True"/>
<Border x:Name="ContentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentTemplate="{TemplateBinding SelectedContentTemplate}" Content="{TemplateBinding SelectedContent}" ContentStringFormat="{TemplateBinding SelectedContentStringFormat}" ContentSource="SelectedContent" Margin="0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="TabStripPlacement" Value="Bottom">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="1"/>
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Left">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="HeaderPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="ContentPanel" Value="1"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Right">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="HeaderPanel" Value="1"/>
<Setter Property="Grid.Column" TargetName="ContentPanel" Value="0"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
复制代码

即使这样设置了,TabControl的标题还是很丑,这个时候就需要通过设置TabItem来更改标题样式了。

TabItem样式如下:


<Style x:Key="TabItemStyle" TargetType="{x:Type TabItem}">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="#FFACACAC"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid x:Name="templateRoot" SnapsToDevicePixels="True" Background="Transparent">
<TextBlock x:Name="txt" Visibility="Visible" VerticalAlignment="Center" HorizontalAlignment="Center" Text="{TemplateBinding Header}" ToolTip="{TemplateBinding Header}" Foreground="{TemplateBinding Foreground}" TextTrimming="CharacterEllipsis" />
</Grid>
<ControlTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="true"/>
<Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Top"/>
</MultiDataTrigger.Conditions> <Setter Property="Foreground" TargetName="txt" Value="#fffea1"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="false"/>
<Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Left"/>
</MultiDataTrigger.Conditions>
<Setter Property="Opacity" TargetName="templateRoot" Value="0.56"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="false"/>
<Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Bottom"/>
</MultiDataTrigger.Conditions>
<Setter Property="Opacity" TargetName="templateRoot" Value="0.56"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="false"/>
<Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Right"/>
</MultiDataTrigger.Conditions>
<Setter Property="Opacity" TargetName="templateRoot" Value="0.56"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="false"/>
<Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Top"/>
</MultiDataTrigger.Conditions>
<Setter Property="Opacity" TargetName="templateRoot" Value="0.56"/>
</MultiDataTrigger> <MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="true"/>
<Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Top"/>
</MultiDataTrigger.Conditions>
<Setter Property="Panel.ZIndex" Value="1"/>
<Setter Property="Foreground" TargetName="txt" Value="#fffea1"/>
</MultiDataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
复制代码

至此,样式已经设置完毕,引用示例:


<Grid Background="#858586">
<TabControl Style="{StaticResource TabControlStyle}" Width="300" Height="200" Background="Transparent" BorderBrush="Transparent" BorderThickness="0">
<TabItem Style="{StaticResource TabItemStyle}" Cursor="Hand" Header="音乐电台" Height="38" >
<Grid Background="#33ffffff">
<TextBlock Text="音乐电台" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</TabItem>
<TabItem Style="{StaticResource TabItemStyle}" Cursor="Hand" Header="Mv电台" Height="38" >
<Grid Background="#33ffffff">
<TextBlock Text="Mv电台" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</TabItem>
</TabControl>
</Grid>
复制代码

效果如下:

三、实现TabControl标题居中显示(不平均分布)

同理需要更改TabControl的样式和TabItem的样式。需要把使用TabPanel作为标题的容器,设置HorizontalAlignment为Center;

TabControl的样式如下:


<Style x:Key="TabControlWithUnderLineStyle" TargetType="{x:Type TabControl}">
<Setter Property="Padding" Value="2"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Background" Value="White"/>
<Setter Property="BorderBrush" Value="#FFACACAC"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<Grid x:Name="templateRoot" ClipToBounds="True" SnapsToDevicePixels="True" 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>
<TabPanel x:Name="HeaderPanel" HorizontalAlignment="Center" Background="Transparent" Grid.Column="0" IsItemsHost="True" Margin="0" Grid.Row="0" KeyboardNavigation.TabIndex="1" Panel.ZIndex="1"/>
<Line X1="0" X2="{Binding ActualWidth, RelativeSource={RelativeSource Self}}" Stroke="Gray" StrokeThickness="0.1" VerticalAlignment="Bottom" Margin="0 0 0 1" SnapsToDevicePixels="True"/>
<Border x:Name="ContentPanel" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Column="0" KeyboardNavigation.DirectionalNavigation="Contained" Grid.Row="1" KeyboardNavigation.TabIndex="2" KeyboardNavigation.TabNavigation="Local">
<ContentPresenter x:Name="PART_SelectedContentHost" ContentTemplate="{TemplateBinding SelectedContentTemplate}" Content="{TemplateBinding SelectedContent}" ContentStringFormat="{TemplateBinding SelectedContentStringFormat}" ContentSource="SelectedContent" Margin="0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="TabStripPlacement" Value="Bottom">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="1"/>
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="Auto"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Left">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="HeaderPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="ContentPanel" Value="1"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="Auto"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
</Trigger>
<Trigger Property="TabStripPlacement" Value="Right">
<Setter Property="Grid.Row" TargetName="HeaderPanel" Value="0"/>
<Setter Property="Grid.Row" TargetName="ContentPanel" Value="0"/>
<Setter Property="Grid.Column" TargetName="HeaderPanel" Value="1"/>
<Setter Property="Grid.Column" TargetName="ContentPanel" Value="0"/>
<Setter Property="Width" TargetName="ColumnDefinition0" Value="*"/>
<Setter Property="Width" TargetName="ColumnDefinition1" Value="Auto"/>
<Setter Property="Height" TargetName="RowDefinition0" Value="*"/>
<Setter Property="Height" TargetName="RowDefinition1" Value="0"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="TextElement.Foreground" TargetName="templateRoot" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
复制代码

TabItem样式如下:


<Style x:Key="TabItemExWithUnderLineStyle" TargetType="{x:Type TabItem}">
<Setter Property="Foreground" Value="White"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="#FFACACAC"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid x:Name="templateRoot" SnapsToDevicePixels="True" Background="Transparent">
<Border x:Name="_underline" BorderBrush="#37aefe" BorderThickness="0" Margin="{TemplateBinding Margin}"/>
<Grid>
<TextBlock x:Name="txt" Visibility="Visible" VerticalAlignment="Center" HorizontalAlignment="Center" Text="{TemplateBinding Header}" ToolTip="{TemplateBinding Header}" Foreground="{TemplateBinding Foreground}" TextTrimming="CharacterEllipsis" />
</Grid>
</Grid>
<ControlTemplate.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsMouseOver, RelativeSource={RelativeSource Self}}" Value="true"/>
<Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Top"/>
</MultiDataTrigger.Conditions> <Setter Property="Foreground" TargetName="txt" Value="#37aefe"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="false"/>
<Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Left"/>
</MultiDataTrigger.Conditions>
<Setter Property="Opacity" TargetName="templateRoot" Value="0.56"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="false"/>
<Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Bottom"/>
</MultiDataTrigger.Conditions>
<Setter Property="Opacity" TargetName="templateRoot" Value="0.56"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="false"/>
<Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Right"/>
</MultiDataTrigger.Conditions>
<Setter Property="Opacity" TargetName="templateRoot" Value="0.56"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsEnabled, RelativeSource={RelativeSource Self}}" Value="false"/>
<Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Top"/>
</MultiDataTrigger.Conditions>
<Setter Property="Opacity" TargetName="templateRoot" Value="0.56"/>
</MultiDataTrigger> <MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding IsSelected, RelativeSource={RelativeSource Self}}" Value="true"/>
<Condition Binding="{Binding TabStripPlacement, RelativeSource={RelativeSource FindAncestor, AncestorLevel=1, AncestorType={x:Type TabControl}}}" Value="Top"/> </MultiDataTrigger.Conditions>
<Setter Property="Panel.ZIndex" Value="1"/>
<Setter Property="Foreground" TargetName="txt" Value="#37aefe"/>
<Setter Property="BorderThickness" TargetName="_underline" Value="0 0 0 2"/>
</MultiDataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
复制代码

引用示例:


<Grid Background="#858586">
<TabControl Style="{StaticResource TabControlWithUnderLineStyle}" Foreground="Black" Width="300" Height="200" Background="Transparent" BorderBrush="Transparent" BorderThickness="0">
<TabItem Style="{StaticResource TabItemExWithUnderLineStyle}" Cursor="Hand" Header="音乐电台" Height="38" Width="70" Margin="5 0">
<Grid Background="#33ffffff">
<TextBlock Text="音乐电台" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</TabItem>
<TabItem Style="{StaticResource TabItemExWithUnderLineStyle}" Cursor="Hand" Header="Mv电台" Height="38" Width="70" Margin="5 0">
<Grid Background="#33ffffff">
<TextBlock Text="Mv电台" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</TabItem>
</TabControl>
</Grid>
复制代码

效果如下:

四、带关闭按钮的TabControl

带关闭按钮的TabControl其实就是就是扩展TabItem,需要新建WPF自定义控件,命名为TabItemClose吧;

C#代码如下:


public class TabItemClose : TabItem
{
static TabItemClose()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TabItemClose), new FrameworkPropertyMetadata(typeof(TabItemClose)));
} private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
d.SetValue(e.Property, e.NewValue);
} /// <summary>
/// 是否可以关闭
/// </summary>
public bool IsCanClose
{
get { return (bool)GetValue(IsCanCloseProperty); }
set { SetValue(IsCanCloseProperty, value); }
} public static readonly DependencyProperty IsCanCloseProperty =
DependencyProperty.Register("IsCanClose", typeof(bool), typeof(TabItemClose), new PropertyMetadata(true, OnPropertyChanged)); /// <summary>
/// 关闭的图标
/// </summary>
public ImageSource CloseIcon
{
get { return (ImageSource)GetValue(CloseIconProperty); }
set { SetValue(CloseIconProperty, value); }
} public static readonly DependencyProperty CloseIconProperty =
DependencyProperty.Register("CloseIcon", typeof(ImageSource), typeof(TabItemClose), new PropertyMetadata(null, OnPropertyChanged)); /// <summary>
/// 正常背景色
/// </summary>
public SolidColorBrush NormalBackground
{
get { return (SolidColorBrush)GetValue(NormalBackgroundProperty); }
set { SetValue(NormalBackgroundProperty, value); }
} public static readonly DependencyProperty NormalBackgroundProperty =
DependencyProperty.Register("NormalBackground", typeof(SolidColorBrush), typeof(TabItemClose), new PropertyMetadata(null, OnPropertyChanged)); /// <summary>
/// 悬浮背景色
/// </summary>
public SolidColorBrush OverBackgound
{
get { return (SolidColorBrush)GetValue(OverBackgoundProperty); }
set { SetValue(OverBackgoundProperty, value); }
} public static readonly DependencyProperty OverBackgoundProperty =
DependencyProperty.Register("OverBackgound", typeof(SolidColorBrush), typeof(TabItemClose), new PropertyMetadata(null, OnPropertyChanged)); /// <summary>
/// 选中背景色
/// </summary>
public SolidColorBrush SelectedBackgound
{
get { return (SolidColorBrush)GetValue(SelectedBackgoundProperty); }
set { SetValue(SelectedBackgoundProperty, value); }
} public static readonly DependencyProperty SelectedBackgoundProperty =
DependencyProperty.Register("SelectedBackgound", typeof(SolidColorBrush), typeof(TabItemClose), new PropertyMetadata(null, OnPropertyChanged)); /// <summary>
/// 默认前景色
/// </summary>
public SolidColorBrush NormalForeground
{
get { return (SolidColorBrush)GetValue(NormalForegroundProperty); }
set { SetValue(NormalForegroundProperty, value); }
} public static readonly DependencyProperty NormalForegroundProperty =
DependencyProperty.Register("NormalForeground", typeof(SolidColorBrush), typeof(TabItemClose), new PropertyMetadata(null, OnPropertyChanged)); /// <summary>
/// 悬浮前景色
/// </summary>
public SolidColorBrush OverForeground
{
get { return (SolidColorBrush)GetValue(OverForegroundProperty); }
set { SetValue(OverForegroundProperty, value); }
} public static readonly DependencyProperty OverForegroundProperty =
DependencyProperty.Register("OverForeground", typeof(SolidColorBrush), typeof(TabItemClose), new PropertyMetadata(null, OnPropertyChanged)); /// <summary>
/// 选中前景色
/// </summary>
public SolidColorBrush SelectedForeground
{
get { return (SolidColorBrush)GetValue(SelectedForegroundProperty); }
set { SetValue(SelectedForegroundProperty, value); }
} public static readonly DependencyProperty SelectedForegroundProperty =
DependencyProperty.Register("SelectedForeground", typeof(SolidColorBrush), typeof(TabItemClose), new PropertyMetadata(null, OnPropertyChanged));
/// <summary>
/// 控件圆角
/// </summary>
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
public static readonly DependencyProperty CornerRadiusProperty =
DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(TabItemClose), new PropertyMetadata(new CornerRadius(0), OnPropertyChanged));
/// <summary>
/// 前置Logo
/// </summary>
public ImageSource LogoIcon
{
get { return (ImageSource)GetValue(LogoIconProperty); }
set { SetValue(LogoIconProperty, value); }
}
public static readonly DependencyProperty LogoIconProperty =
DependencyProperty.Register("LogoIcon", typeof(ImageSource), typeof(TabItemClose), new PropertyMetadata(null, OnPropertyChanged));
/// <summary>
/// 前置Logo宽度
/// </summary>
public double LogoIconWidth
{
get { return (double)GetValue(LogoIconWidthProperty); }
set { SetValue(LogoIconWidthProperty, value); }
}
public static readonly DependencyProperty LogoIconWidthProperty =
DependencyProperty.Register("LogoIconWidth", typeof(double), typeof(TabItemClose), new PropertyMetadata(double.Parse("0"), OnPropertyChanged));
/// <summary>
/// 前置Logo高度
/// </summary>
public double LogoIconHeigth
{
get { return (double)GetValue(LogoIconHeigthProperty); }
set { SetValue(LogoIconHeigthProperty, value); }
}
public static readonly DependencyProperty LogoIconHeigthProperty =
DependencyProperty.Register("LogoIconHeigth", typeof(double), typeof(TabItemClose), new PropertyMetadata(double.Parse("0"), OnPropertyChanged));
/// <summary>
/// LogoPadding
/// </summary>
public Thickness LogoPadding
{
get { return (Thickness)GetValue(LogoPaddingProperty); }
set { SetValue(LogoPaddingProperty, value); }
} public static readonly DependencyProperty LogoPaddingProperty =
DependencyProperty.Register("LogoPadding", typeof(Thickness), typeof(TabItemClose), new PropertyMetadata(new Thickness(0), OnPropertyChanged));
/// <summary>
/// 关闭item事件
/// </summary>
public event RoutedEventHandler CloseItem
{
add { AddHandler(CloseItemEvent, value); }
remove { RemoveHandler(CloseItemEvent, value); }
}
public static readonly RoutedEvent CloseItemEvent =
EventManager.RegisterRoutedEvent("CloseItem", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TabItemClose));
/// <summary>
/// 关闭项的右键菜单
/// </summary>
public ContextMenu ItemContextMenu { get; set; } Border ItemBorder;
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
ItemBorder = Template.FindName("_bordertop", this) as Border;
if (ItemContextMenu != null)
{
ItemBorder.ContextMenu = ItemContextMenu;
}
}
}
复制代码

这里面我们添加了很多扩展功能,包括右键菜单,图标显示和控件圆角,以及各种背景色属性。

然后为TabItemClose设置样式


<Style TargetType="{x:Type local:TabItemClose}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="Foreground" Value="#666666"/>
<Setter Property="Margin" Value="0 0 0 0"/>
<Setter Property="Padding" Value="0"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="CloseIcon" Value="/Images/close2.png"/>
<Setter Property="NormalBackground" Value="White"/>
<Setter Property="OverBackgound" Value="#33ca5100"/>
<Setter Property="SelectedBackgound" Value="#ca5100"/>
<Setter Property="NormalForeground" Value="#555558"/>
<Setter Property="OverForeground" Value="White"/>
<Setter Property="SelectedForeground" Value="White"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:TabItemClose}">
<Border x:Name="_bordertop" Width="{TemplateBinding Width}" MaxWidth="{TemplateBinding MaxWidth}" Height="{TemplateBinding Height}" CornerRadius="{TemplateBinding CornerRadius}" Background="{TemplateBinding NormalBackground}" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" ToolTip="{TemplateBinding Header}" >
<DockPanel>
<Image x:Name="_logo" DockPanel.Dock="Left" Visibility="Visible" Margin="{TemplateBinding LogoPadding}" Source="{TemplateBinding LogoIcon}" VerticalAlignment="Center" HorizontalAlignment="Center" Stretch="Uniform" Width="{TemplateBinding LogoIconWidth}" Height="{TemplateBinding LogoIconHeigth}" />
<Grid Name="_grid" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition x:Name="_col_close" Width="20" />
</Grid.ColumnDefinitions>
<Border Grid.ColumnSpan="2" Background="White" Opacity="0"/>
<TextBlock x:Name="_txt" VerticalAlignment="Center" TextTrimming="CharacterEllipsis" Margin="3 0 3 0" Foreground="{TemplateBinding NormalForeground}" TextAlignment="Center" HorizontalAlignment="Center" Text="{TemplateBinding Header}" />
<Grid x:Name="_gridclose" Grid.Column="1" >
<Border x:Name="_borderbg" Background="Black" Opacity="0" />
<local:ButtonEx x:Name="PART_Close_TabItem" HorizontalAlignment="Center" VerticalAlignment="Center" Background="Transparent" Visibility="Visible" Icon="{TemplateBinding CloseIcon}" ButtonType="Icon" />
</Grid>
</Grid>
</DockPanel> </Border>
<ControlTemplate.Triggers>
<Trigger Property="LogoIcon" Value="{x:Null}">
<Setter TargetName="_logo" Property="Visibility" Value="Collapsed" />
</Trigger>
<Trigger Property="IsCanClose" Value="false">
<Setter TargetName="_gridclose" Property="Visibility" Value="Collapsed"/>
<Setter TargetName="_col_close" Property="Width" Value="0"/>
</Trigger>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="_bordertop" Property="Background" Value="{Binding SelectedBackgound,RelativeSource={RelativeSource TemplatedParent}}" />
<Setter TargetName="_txt" Property="Foreground" Value="{Binding SelectedForeground,RelativeSource={RelativeSource TemplatedParent}}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="true"/>
<Condition Property="IsSelected" Value="false"/>
</MultiTrigger.Conditions>
<Setter TargetName="_txt" Property="Foreground" Value="{Binding OverForeground,RelativeSource={RelativeSource TemplatedParent}}"/>
<Setter TargetName="_bordertop" Property="Background" Value="{Binding OverBackgound,RelativeSource={RelativeSource TemplatedParent}}"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
复制代码

这里面使用了一个close的图标

TabControl的图标可设置可不设置,看自己需要。

这里面还用到了前面讲的控件ButtonEx,定义方法我就不重复赘述了。大家可以通过这个链接跳转查看:。ButtonEx.cs里面还要添加几个方法用来支持关闭TabItem:


protected override void OnClick()
{
base.OnClick();
if (!string.IsNullOrEmpty(Name) && Name == "PART_Close_TabItem")
{
TabItemClose itemclose = FindVisualParent<TabItemClose>(this);
(itemclose.Parent as TabControl).Items.Remove(itemclose);
RoutedEventArgs args = new RoutedEventArgs(TabItemClose.CloseItemEvent, itemclose);
itemclose.RaiseEvent(args);
}
} public static T FindVisualParent<T>(DependencyObject obj) where T : class
{
while (obj != null)
{
if (obj is T)
return obj as T; obj = VisualTreeHelper.GetParent(obj);
}
return null;
}
复制代码

引用示例:


<Grid Background="#858586">
<TabControl Foreground="Black" Width="300" Height="200" Background="Transparent" BorderBrush="Transparent" BorderThickness="0">
<local:TabItemClose Cursor="Hand" Header="音乐电台" Height="20" Width="100">
<Grid Background="#aaffffff">
<TextBlock Text="音乐电台" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</local:TabItemClose>
<local:TabItemClose Cursor="Hand" Header="Mv电台" Height="20" Width="100">
<Grid Background="#aaffffff">
<TextBlock Text="Mv电台" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</local:TabItemClose>
</TabControl>
</Grid>
复制代码

效果如下:

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对编程学习网的支持。

WPF如何自定义TabControl控件样式示例详解的更多相关文章

  1. WPF 自定义TabControl控件样式

    一.前言 程序中经常会用到TabControl控件,默认的控件样式很普通.而且样式或功能不一定符合我们的要求.比如:我们需要TabControl的标题能够居中.或平均分布:或者我们希望TabContr ...

  2. arcgis api for js共享干货系列之二自定义Navigation控件样式风格

    arcgis api for js默认的Navigation控件样式风格如下图: 这样的风格不能说不好,各有各的爱好,审美观,这里也不是重点,这里的重点是如何自定义一套自己喜欢的样式风格呢:自己自定义 ...

  3. arcgis api 3.x for js 共享干货系列之二自定义 Navigation 控件样式风格(附源码下载)

    0.内容概览 自定义 Navigation 控件样式风格 源码下载 1.内容讲解 arcgis api 3.x for js 默认的Navigation控件样式风格如下图:这样的风格不能说不好,各有各 ...

  4. 《手把手教你》系列技巧篇(三十八)-java+ selenium自动化测试-日历时间控件-下篇(详解教程)

    1.简介 理想很丰满现实很骨感,在应用selenium实现web自动化时,经常会遇到处理日期控件点击问题,手工很简单,可以一个个点击日期控件选择需要的日期,但自动化执行过程中,完全复制手工这样的操作就 ...

  5. WPF自定义分页控件,样式自定义,简单易用

    WPF自定义分页控件 做了许久伸手党,终于有机会贡献一波,搜索一下WPF分页控件,还是多,但是不太通用,主要就是样式问题,这个WPF很好解决,还有一个就是分页控件嘛,只关心几个数字的变动就行了,把页码 ...

  6. Android自定义组合控件详细示例 (附完整源码)

    在我们平时的Android开发中,有时候原生的控件无法满足我们的需求,或者经常用到几个控件组合在一起来使用.这个时候,我们就可以根据自己的需求创建自定义的控件了,一般通过继承View或其子类来实现. ...

  7. delphi控件属性大全-详解-简介

    http://blog.csdn.net/u011096030/article/details/18716713 button 组件: CAPTION 属性 :用于在按钮上显示文本内容 Cancel ...

  8. wpf 自定义RadioButton控件样式

    实现的效果为: 我感觉来自定义RadioButton样式和定义button空间的样式差不多,只是类型不同而已. 接下来分析一下样式代码: <!--自定义单选按钮样式-->        & ...

  9. WPF 自定义DataGrid控件样式

    内容转自https://www.cnblogs.com/xiaogangqq123/archive/2012/05/07/2487166.html 一.DataGrid基本样式(一) 小刚已经把Dat ...

  10. WPF 自定义TreeView控件样式,仿QQ联系人列表

    一.前言 TreeView控件在项目中使用比较频繁,普通的TreeView并不能满足我们的需求.因此我们需要滴对TreeView进行改造.下面的内容将介绍仿QQ联系人TreeView样式及TreeVi ...

随机推荐

  1. PyTorch分分钟快速安装

    PyTorch的前身是Torch,其底层和Torch框架一样,但是使用Python重新写了很多内容,不仅更加灵活,支持动态图,而且提供了Python接口. 它是由Torch7团队开发,是一个以Pyth ...

  2. Linux下的权限(角色,文件权限)

    目录 1.什么是权限 2.文件类型及权限 ①Linux文件类型: ②剩余9个字符对应的含义: ③文件权限值的表示方法(进制法) 3.如何操作权限 3.1改变权限的命令操作 chmod #change ...

  3. vscode下的超级慢的解决方法

    vscode下的超级慢的解决方法 从网上看到的方法,记录给自己看 vscode官网:https://code.visualstudio.com/Download 复制下载链接 链接如下: https: ...

  4. 力扣385(java)-迷你语法分析器(中等)

    题目: 给定一个字符串 s 表示一个整数嵌套列表,实现一个解析它的语法分析器并返回解析的结果 NestedInteger . 列表中的每个元素只可能是整数或整数嵌套列表 示例 1: 输入:s = &q ...

  5. 【阿里云采购季】3月采购完,IT运维躺赢一年2

    阿里云2020上云采购季正式上线啦!今年的采购季可以逛些啥?    采购季正式期时间: 3月2日-3月31日 在这段时间里,想买啥就买吧,别忘了把想买的产品加入购物车噢,特惠产品叠加购物车满减,更划算 ...

  6. 写给大家看的“不负责任” K8s 入门文档

    前言 2019 年下半年,我做了一次转岗,开始接触到 Kubernetes,虽然对 K8s 的认识还非常的不全面,但是非常想分享一下自己的一些收获,希望通过本文能够帮助大家对 K8s 有一个入门的了解 ...

  7. 阿里云 EMR Delta Lake 在流利说数据接入中的架构和实践

    简介: 为了消灭数据孤岛,企业往往会把各个组织的数据都接入到数据湖以提供统一的查询或分析.本文将介绍流利说当前数据接入的整个过程,期间遇到的挑战,以及delta在数据接入中产生的价值. 背景 流利说目 ...

  8. 1小时打造HaaS版小小蛮驴智能车

    简介: 2020年云栖大会上,阿里云发布了一款机器人"小蛮驴",瞬间激起千层浪,无人车,智能物流,机器人等一些概念又火热了一把. 借"小蛮驴"的东风以及火热的H ...

  9. Flagger on ASM——基于Mixerless Telemetry实现渐进式灰度发布系列 2 应用级扩缩容

    简介: 应用级扩缩容是相对于运维级而言的.像监控CPU/内存的利用率就属于应用无关的纯运维指标,针对这种指标进行扩缩容的HPA配置就是运维级扩缩容.而像请求数量.请求延迟.P99分布等指标就属于应用相 ...

  10. Dubbo 和 HSF 在阿里巴巴的实践:携手走向下一代云原生微服务

    ​简介: HSF 和 Dubbo 的融合是大势所趋.为了能更好的服务内外用户,也为了两个框架更好发展,Dubbo 3.0 和以 Dubbo 3.0 为内核适配集团内基础架构生态的 HSF 3 应运而生 ...