WPF 自定义TabControl

自定义样式效果如下:

整体实现思路首先自定义UTabControl、然后自定义TabItem

1、UTabControl.cs 代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;


namespace YOI.Controls
{
public class UTabControl : TabControl
{
static UTabControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(UTabControl), new FrameworkPropertyMetadata(typeof(UTabControl)));
}


/// <summary>
/// 方向枚举
/// </summary>
public enum OrientationEnum
{
Left,
Right,
Middle
}




public HorizontalAlignment TabHorizontalAlignment
{
get { return (HorizontalAlignment)GetValue(TabHorizontalAlignmentProperty); }
set { 


SetValue(TabHorizontalAlignmentProperty, value);

}
}


public static readonly DependencyProperty TabHorizontalAlignmentProperty =
DependencyProperty.Register("TabHorizontalAlignment", typeof(HorizontalAlignment), typeof(UTabControl), new PropertyMetadata(HorizontalAlignment.Left, TabHorizontalAlignmentChanged));

private static void TabHorizontalAlignmentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
object oldValue = (object)e.OldValue;
object newValue = (object)e.NewValue;
var uTabControl = (UTabControl)d;
if (oldValue != newValue)
{
switch (newValue)
{
case HorizontalAlignment.Right:

uTabControl.TabHorizontalAlignment = HorizontalAlignment.Right;

break;
case HorizontalAlignment.Center:
uTabControl.TabHorizontalAlignment = HorizontalAlignment.Center;
break;
case HorizontalAlignment.Left:
uTabControl.TabHorizontalAlignment = HorizontalAlignment.Left;
break;
default:
break;
}
}
}
}
}

2、UTabControl模板资源样式

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:MotionControls.Controls">

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



</ResourceDictionary>

3、UTabItem 代码

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace YOI.Controls
{
public class UTabItem : TabItem
{
static UTabItem()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(UTabItem), new FrameworkPropertyMetadata(typeof(UTabItem)));
}


/// <summary>
/// 选中字体颜色
/// </summary>
public SolidColorBrush ActiveForeground
{
get { return (SolidColorBrush)GetValue(ActiveForegroundProperty); }
set { SetValue(ActiveForegroundProperty, value); }
}


/// <summary>
/// 未选中字体颜色
/// </summary>
[Category("自定义"), Description("该属性用于调整内部文字的未选中字体颜色")]
public SolidColorBrush InactiveForeground
{
get { return (SolidColorBrush)GetValue(InactiveForegroundProperty); }
set { SetValue(InactiveForegroundProperty, value); }
}


/// <summary>
/// 选中字体颜色
/// </summary>
public SolidColorBrush ActiveIndicatorColor
{
get { return (SolidColorBrush)GetValue(ActiveIndicatorColorProperty); }
set { SetValue(ActiveIndicatorColorProperty, value); }
}


public static readonly DependencyProperty ActiveIndicatorColorProperty =
DependencyProperty.Register("ActiveIndicatorColor", typeof(SolidColorBrush), typeof(UTabItem), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(172, 172, 172))));


public static readonly DependencyProperty InactiveForegroundProperty =
DependencyProperty.Register("InactiveForeground", typeof(SolidColorBrush), typeof(UTabItem), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(172, 172, 172))));


public static readonly DependencyProperty ActiveForegroundProperty =
DependencyProperty.Register("ActiveForeground", typeof(SolidColorBrush), typeof(UTabItem), new PropertyMetadata(new SolidColorBrush(Color.FromRgb(67, 67, 68))));
}
}

4、UTabItem 模板资源样式

<ResourceDictionary
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:local="clr-namespace:MotionControls.Controls">


  <Style TargetType="{x:Type local:UTabItem}">

    <Setter Property="FontSize" Value="16" />
    <Setter Property="HorizontalContentAlignment" Value="Stretch" />
    <Setter Property="VerticalContentAlignment" Value="Stretch" />

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

          <Grid
            x:Name="templateRoot"
            Background="{TemplateBinding Background}"
            SnapsToDevicePixels="true">
            <Border
              x:Name="mainBorder"
              Margin="{TemplateBinding Margin}"
              Background="{TemplateBinding Background}"
              BorderBrush="{TemplateBinding BorderBrush}"
              BorderThickness="0"
              CornerRadius="1" />

            <Rectangle
              x:Name="Indicator"
              Width="25"
              Height="2.5"
              VerticalAlignment="Bottom"
              RadiusX="2.5"
              RadiusY="2.5" />


            <Grid>
              <TextBlock
                x:Name="txt"
                Padding="{TemplateBinding Padding}"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                Cursor="Hand"
                FontWeight="{TemplateBinding FontWeight}"
                Foreground="{Binding InactiveForeground, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                Text="{TemplateBinding Header}"
                TextTrimming="CharacterEllipsis"
                ToolTip="{TemplateBinding Header}"
                Visibility="Visible" />
            </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 TargetName="txt" Property="Foreground" Value="{DynamicResource TextPrimaryColor}" />

            </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 TargetName="templateRoot" Property="Opacity" 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 local:UTabControl}}}" Value="Top" />
            </MultiDataTrigger.Conditions>
              <Setter Property="Panel.ZIndex" Value="1" />
              <Setter TargetName="txt" Property="Foreground" Value="{Binding ActiveForeground, RelativeSource={RelativeSource Mode=TemplatedParent}}" />

              <!--<Setter TargetName="mainBorder" Property="Background" Value="{DynamicResource PrimaryBlueColor}" />-->

              <!--<Setter TargetName="mainBorder" Property="Opacity" Value="0.8" />-->

              <Setter TargetName="Indicator" Property="Fill" Value="{Binding ActiveIndicatorColor, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
              <!--<Setter TargetName="mainBorder" Property="BorderThickness" Value="0,0,0,2" />-->

              <MultiDataTrigger.EnterActions>
              <BeginStoryboard>
              <Storyboard>
              <DoubleAnimation
              Storyboard.TargetName="Indicator"
              Storyboard.TargetProperty="Width"
              From="25"
              To="40"
              Duration="0:0:0.3" />
            </Storyboard>
            </BeginStoryboard>
            </MultiDataTrigger.EnterActions>


              <MultiDataTrigger.ExitActions>
              <BeginStoryboard>
              <Storyboard>
              <DoubleAnimation
              Storyboard.TargetName="Indicator"
              Storyboard.TargetProperty="Width"
              From="40"
              To="25"
              Duration="0:0:0.3" />
            </Storyboard>
            </BeginStoryboard>
            </MultiDataTrigger.ExitActions>
            </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 local:UTabControl}}}" Value="Left" />
            </MultiDataTrigger.Conditions>
              <Setter Property="Panel.ZIndex" Value="1" />
              <Setter TargetName="txt" Property="Foreground" Value="{Binding ActiveForeground, RelativeSource={RelativeSource Mode=TemplatedParent}}" />

              <!--<Setter TargetName="mainBorder" Property="Background" Value="{DynamicResource PrimaryBlueColor}" />-->

              <!--<Setter TargetName="mainBorder" Property="Opacity" Value="0.8" />-->

              <Setter TargetName="Indicator" Property="Fill" Value="{Binding ActiveIndicatorColor, RelativeSource={RelativeSource Mode=TemplatedParent}}" />
              <!--<Setter TargetName="mainBorder" Property="BorderThickness" Value="0,0,0,2" />-->

              <MultiDataTrigger.EnterActions>
              <BeginStoryboard>
              <Storyboard>
              <DoubleAnimation
              Storyboard.TargetName="Indicator"
              Storyboard.TargetProperty="Width"
              From="25"
              To="40"
              Duration="0:0:0.3" />
            </Storyboard>
            </BeginStoryboard>
            </MultiDataTrigger.EnterActions>


              <MultiDataTrigger.ExitActions>
              <BeginStoryboard>
              <Storyboard>
              <DoubleAnimation
              Storyboard.TargetName="Indicator"
              Storyboard.TargetProperty="Width"
              From="40"
              To="25"
              Duration="0:0:0.3" />
            </Storyboard>
            </BeginStoryboard>
            </MultiDataTrigger.ExitActions>
            </MultiDataTrigger>
            </Setter.Value>
            </Setter>
            </Style>
            </ResourceDictionary>

5、调用方式

       <YOI:UTabControl
                    Width="Auto"
                    Height="Auto"
                    HorizontalAlignment="Stretch"
                    VerticalAlignment="Stretch"
                    Background="{DynamicResource PrimaryBackgroundColor}"
                    BorderBrush="Transparent"
                    BorderThickness="0,0,0,0"
                    TabHorizontalAlignment="Center"
                    TabStripPlacement="Top">

                    <YOI:UTabItem
                        Width="100"
                        Height="38"
                        VerticalAlignment="Top"
                        ActiveForeground="{DynamicResource TextBlueColor}"
                        ActiveIndicatorColor="{DynamicResource TextBlueColor}"
                        Background="{DynamicResource TextTransparentColor}"
                        BorderBrush="{DynamicResource TextTransparentColor}"
                        Foreground="{DynamicResource TextWhiteColor}"
                        Header="参数1"
                        InactiveForeground="{DynamicResource TextGrayColor}">

                        <Grid
                            Margin="1"
                            HorizontalAlignment="Stretch"
                            VerticalAlignment="Stretch"
                            Background="{DynamicResource SecundaryGrayColor}">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="544*" />
                                <ColumnDefinition Width="20*" />
                                <ColumnDefinition Width="121*" />
                                <ColumnDefinition Width="100*" />
                                <ColumnDefinition Width="213*" />
                            </Grid.ColumnDefinitions>

                         <ContentControl Grid.ColumnSpan="5" prism:RegionManager.RegionName="{x:Static ext:PrismManager.MotionViewRegionName}" />

                        </Grid>
                    </YOI:UTabItem>
                </YOI:UTabControl>

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
WPF 中,可以通过使用动态数据绑定来实现动态 TabControl。下面是一个简单的示例,展示如何通过绑定动态集合来实现动态添加和删除 TabItem: 首先,在 XAML 文件中,创建一个 TabControl,并绑定一个动态集合作为 ItemsSource: ```xml <TabControl ItemsSource="{Binding TabItems}"> <TabControl.ContentTemplate> <DataTemplate> <!-- 这里是 TabItem 的内容 --> <TextBlock Text="{Binding Title}" /> </DataTemplate> </TabControl.ContentTemplate> </TabControl> ``` 接下来,在代码后台(ViewModel)中,创建一个 ObservableCollection 来存储 TabItem 对象: ```csharp public class MainViewModel : INotifyPropertyChanged { public ObservableCollection<TabItem> TabItems { get; set; } public MainViewModel() { TabItems = new ObservableCollection<TabItem>(); } // 添加一个新的 TabItem public void AddTabItem(string title) { TabItems.Add(new TabItem { Title = title }); } // 删除指定的 TabItem public void RemoveTabItem(TabItem tabItem) { TabItems.Remove(tabItem); } // 实现 INotifyPropertyChanged 接口... } ``` 在上述代码中,TabItem 是一个简单的自定义类,具有一个 Title 属性: ```csharp public class TabItem { public string Title { get; set; } } ``` 最后,在窗口的代码后台(Code-Behind)中,设置 DataContext 并调用 ViewModel 的方法来添加或删除 TabItem: ```csharp public partial class MainWindow : Window { private MainViewModel _viewModel; public MainWindow() { InitializeComponent(); _viewModel = new MainViewModel(); DataContext = _viewModel; } private void AddTabButton_Click(object sender, RoutedEventArgs e) { _viewModel.AddTabItem("New Tab"); } private void RemoveTabButton_Click(object sender, RoutedEventArgs e) { var tabItem = TabControl.SelectedItem as TabItem; if (tabItem != null) { _viewModel.RemoveTabItem(tabItem); } } } ``` 现在,当单击 "Add Tab" 按钮时,将会动态添加一个新的 TabItem。当选中某个 TabItem 后,再单击 "Remove Tab" 按钮,将会删除选中的 TabItem。这样就实现了动态的 TabControl
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值