WPF 自定义TabControl控件样式

一、前言

程序中经常会用到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,定义方法我就不重复赘述了。大家可以通过这个链接跳转查看:http://www.cnblogs.com/xiaomingg/p/8699125.html。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>

效果如下:

原文地址:https://www.cnblogs.com/xiaomingg/p/8870825.html

时间: 2024-10-09 13:00:53

WPF 自定义TabControl控件样式的相关文章

wpf 自定义RadioButton控件样式

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

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

arcgis api for js默认的Navigation控件样式风格如下图: 这样的风格不能说不好,各有各的爱好,审美观,这里也不是重点,这里的重点是如何自定义一套自己喜欢的样式风格呢:自己自定义一个NavigationControl控件类,最终实现的效果如下图: 思路如下:其实就是在网上参照天地图或者谷歌地图的Navigation风格样式,下载它们的图片模版,然后自己创建div来实现图片的缩放平移.全图.左右上下平移等等地图导航功能: Navigation图片目录如下: 调用函数: //显

WPF编程之自定义Button控件样式

自.NET Framework 3.0 以后,WPF编程框架可使开发人员开发出更加令人耳目一新的桌面应用程序.它使开发工作更加方便快捷,它将设计人员和编程人员的工作分离开来.至于WPF的背景历史.框架特点.框架结构这里就不再赘述.有兴趣的同袍可在百度搜索关于WPF的相关知识介绍,如WPF. 在微软在WPF框架里提供了一些基础功能各异的控件,例如Button.TextBox.Label.Panel.TextBlock等等.微软将这些组件可视化集成到Visual Studio集成开发工具中了,这在实

WPF自定义仪表盘控件

闲来无事,分享一个仪表盘 源码: 直接复制代码即可运行,=.=! <Window x:Class="TGP.InstrumentationDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="h

easyui-datagrid自定义分页控件样式

var p = $('#tbTaskList').datagrid('getPager'); $(p).pagination({ pageSize: 20,//每页显示的记录条数,默认为10 pageList: [20, 50, 100],//可以设置每页记录条数的列表 beforePageText: '第',//页数文本框前显示的汉字 afterPageText: '页 共 {pages} 页', displayMsg: '当前显示 {from} - {to} 条记录 共 {total} 条记

WPF自定义控件(二)の重写原生控件样式模板

开发过程中,我们有时候用WPF原生的控件就能实现自己的需求,但是样式.风格并不能满足我们的需求,那么我们该怎么办呢?----自定义样式与模板. 一.样式 在WPF中我们可以使用Style来设置控件的某些属性值,并使该设置影响到指定范围内的所有该类控件或影响指定的某一控件,比如说我们想将窗口中的所有按钮都保持某一种风格,那么我们可以设置一个Style,而不必分别设置每个按钮的风格.Style是作为一种资源被保存下来的. 看下面的例子: <Style x:Key="style1" T

论如何在手机端web前端实现自定义原生控件的样式

手机开发webapp的同学一定遇到过这样问题,如何为丑极了的手机元素应用自定义的样式.首先,要弄清楚为什么要定义手机原生控件的样式,就需要看看手机的那些原生框样式的丑陋摸样: android: ios: 无奈的选择 看完了这些丑陋的界面元素,我们就可以理解当我们把他们暴露在产品同学的眼中时,那种层层的杀气了.可以看到,界面元素十分丑陋,产品兄弟是肯定不会接受的.但是,不得不说这些控件在触发后的效果比pc机上的要炫酷.这其中以apple机的滚筒选择最为出色.以下是它们触发后调用原生控件的效果: a

WPF的ListView控件自定义布局用法实例

本文实例讲述了WPF的ListView控件自定义布局用法.分享给大家供大家参考,具体如下: 概要: 以源码的形式贴出,免得忘记后,再到网上查资料.在VS2008+SP1环境下调试通过 引用的GrayscaleEffect模块,可根据参考资料<Grayscale Effect...>中的位置下载. 正文: 如何布局是在App.xaml中定义源码如下 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27

Silverlight控件样式——TabControl

写Silverlight程序已有一年有余,一步步走来满是收获却疏于积累与分享.在此空闲时间,将过去重写过的控件样式一一记录,便于查阅,也希望能起到抛砖引玉之效.如有编写和使用上的问题,均可发邮件到zdp06623#163.com(#替换为@)反馈与问询. 控件修改后效果 控件使用注意事项 该控件由系统自带控件TabControl重写而来,样式仿Chorme选项卡.使用过程中需要注意几点: 1.第一个选项卡样式与其他选项卡样式有所差异,需要分别引用FirstGreenTabItemStyle样式和