WPF如何自定义TabControl控件样式示例详解

作者:小明GG 时间:2021-09-22 07:27:34 

一、前言

程序中经常会用到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>

效果如下:

WPF如何自定义TabControl控件样式示例详解

三、实现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>

效果如下:

WPF如何自定义TabControl控件样式示例详解

四、带关闭按钮的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的图标

WPF如何自定义TabControl控件样式示例详解

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

这里面还用到了前面讲的控件ButtonEx,定义方法我就不重复赘述了。大家可以通过这个链接跳转查看:https://www.jb51.net/article/138475.htm。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控件样式示例详解

来源:http://www.cnblogs.com/xiaomingg/p/8870825.html

标签:wpf,tabcontrol,控件
0
投稿

猜你喜欢

  • 深入理解C++中public、protected及private用法

    2023-07-02 11:30:17
  • Spring事务失效的场景梳理总结

    2023-02-23 16:23:24
  • C#实现json的序列化和反序列化实例代码

    2022-07-18 01:50:34
  • linux操作系统安装MONO执行C#程序的详解步骤

    2022-10-04 18:20:04
  • java 多态性详解及常见面试题

    2023-03-15 18:08:49
  • C#简单遍历指定文件夹中所有文件的方法

    2022-12-16 18:42:27
  • java处理图片背景颜色的方法

    2023-11-27 04:38:20
  • C# WebApi 异常处理解决方案

    2021-06-14 16:52:08
  • Java实现Http工具类的封装操作示例

    2021-08-14 10:27:57
  • Android开发获取重力加速度和磁场强度的方法

    2022-05-27 23:07:09
  • JAVA序列化Serializable及Externalizable区别详解

    2022-04-04 10:49:09
  • 解决RestTemplate 请求接收自定义400+ 或500+错误

    2023-12-12 00:25:20
  • Java数组的基本学习教程

    2021-07-14 05:08:00
  • Android画板开发之基本画笔功能

    2023-01-09 07:26:21
  • SpringMVC结构简介及常用注解汇总

    2023-10-25 09:16:59
  • Java 获取当前时间及实现时间倒计时功能【推荐】

    2022-08-21 16:08:27
  • C#调用微信接口的相关代码

    2022-01-23 03:01:02
  • 详解 Corba开发之Java实现Service与Client

    2023-09-23 03:42:48
  • Jenkins安装以及邮件配置详解

    2023-04-20 12:42:39
  • Spring Cloud Feign接口返回流的实现

    2021-06-07 07:21:54
  • asp之家 软件编程 m.aspxhome.com