WPF自定义控件那些事(四)

自定义TabControl与TabItem

 

   很长时间没有写博客了,今天来和大家一起分享一下TabControl自定义。

  在开发系统中,常常需要用到TabControl控件,而且往往需要我们在运行过程中,动态添加与动态删除标签页面,现在就让我们一起来打造这样的TabControl吧。

  主要是通过在TabControl中的标签页中增加一个关闭按钮来实现,是否可关闭可以在TabControl中设置,也可以在TabItem中进行单独设置,关闭按钮只有在鼠标移到标签上或者当前标签才显示。同时和关闭窗口一样,支持即将关闭和关闭后的事件。

  效果图:

 

 

代码:

1、模板文件(ZbTabControl.xaml):

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="
http://schemas.microsoft.com/winfx/2006/xaml"
     xmlns:d="
http://schemas.microsoft.com/expression/blend/2008"
     xmlns:mc="
http://schemas.openxmlformats.org/markup-compatibility/2006"
     xmlns:sys="clr-namespace:System;assembly=mscorlib"
     xmlns:local="clr-namespace:Zbsoft.WpfControls"
     mc:Ignorable="d">

 <ResourceDictionary.MergedDictionaries>
  <ResourceDictionary Source="/Zbsoft.WpfControls;component/Resources/ZbShared.xaml"></ResourceDictionary>
 </ResourceDictionary.MergedDictionaries>

 <!--关闭按钮相关开始-->
 <sys:Double x:Key="CloseButtonWidthAndHeight">14</sys:Double>
 <Geometry x:Key="X_CloseButton">M0,0 L10,10 M0,10 L10,0</Geometry>
 <Color x:Key="TabItem_ForegroundColor_Base">#4971A3</Color>
 <SolidColorBrush x:Key="TabItemCloseButtonNormalForegroundBrush"
                       Color="{StaticResource TabItem_ForegroundColor_Base}"/>
 <SolidColorBrush x:Key="TabItemCloseButtonHoverForegroundBrush"
                       Color="White"/>
 <SolidColorBrush x:Key="TabItemCloseButtonPressedForegroundBrush"
                       Color="#EEEE"/>

 <LinearGradientBrush x:Key="TabItemCloseButtonNormalBackgroundBrush"
                           StartPoint="0,0" EndPoint="1,0">
  <GradientBrush.GradientStops>
   <GradientStopCollection>
    <GradientStop Color="#5FFF" Offset="0.0"/>
    <GradientStop Color="#5CCC" Offset="1.0"/>
   </GradientStopCollection>
  </GradientBrush.GradientStops>
 </LinearGradientBrush>

 <LinearGradientBrush x:Key="TabItemCloseButtonNormalBorderBrush"
                           StartPoint="0,0" EndPoint="1,1">
  <GradientBrush.GradientStops>
   <GradientStopCollection>
    <GradientStop Color="#5CCC" Offset="0.0"/>
    <GradientStop Color="#5444" Offset="1.0"/>
   </GradientStopCollection>
  </GradientBrush.GradientStops>
 </LinearGradientBrush>

 <LinearGradientBrush x:Key="TabItemCloseButtonHoverBackgroundBrush"
                           StartPoint="0,1" EndPoint="1,0">
  <GradientBrush.GradientStops>
   <GradientStopCollection>
    <GradientStop Color="#FFDF2B1E" Offset="0.0"/>
    <GradientStop Color="#FFA41F00" Offset="1.0"/>
   </GradientStopCollection>
  </GradientBrush.GradientStops>
 </LinearGradientBrush>

 <LinearGradientBrush x:Key="TabItemCloseButtonPressedBackgroundBrush"
                           StartPoint="0,0" EndPoint="1,1">
  <GradientBrush.GradientStops>
   <GradientStopCollection>
    <GradientStop Color="#FFA41F00" Offset="0.0"/>
    <GradientStop Color="#FFDF2B1E" Offset="1.0"/>
   </GradientStopCollection>
  </GradientBrush.GradientStops>
 </LinearGradientBrush>

 <LinearGradientBrush x:Key="TabItemCloseButtonPressedBorderBrush"
                           StartPoint="0,0" EndPoint="1,1">
  <GradientBrush.GradientStops>
   <GradientStopCollection>
    <GradientStop Color="#5444" Offset="0.0"/>
    <GradientStop Color="#5CCC" Offset="1.0"/>
   </GradientStopCollection>
  </GradientBrush.GradientStops>
 </LinearGradientBrush>

 <Style x:Key="TabItemCloseButtonStyle" TargetType="{x:Type Button}">

  <Setter Property="SnapsToDevicePixels" Value="false"/>
  <Setter Property="Height" Value="{StaticResource CloseButtonWidthAndHeight}"/>
  <Setter Property="Width" Value="{StaticResource CloseButtonWidthAndHeight}"/>
  <Setter Property="Cursor" Value="Hand"/>
  <Setter Property="Focusable" Value="False"/>
  <Setter Property="OverridesDefaultStyle" Value="true"/>
  <Setter Property="Template">
   <Setter.Value>
    <ControlTemplate TargetType="{x:Type Button}">
     <Border x:Name="ButtonBorder" 
                          CornerRadius="2"
                          BorderThickness="1"
                          Background="{StaticResource TabItemCloseButtonNormalBackgroundBrush}"
                          BorderBrush="{StaticResource TabItemCloseButtonNormalBorderBrush}">
      <Grid>
       <Path x:Name="ButtonPath"
                              Margin="2"
                              Data="{StaticResource X_CloseButton}"
                              Stroke="{StaticResource TabItemCloseButtonNormalForegroundBrush}"
                              StrokeThickness="2"
                              StrokeStartLineCap="Round"
                              StrokeEndLineCap="Round"
                              Stretch="Uniform"
                              VerticalAlignment="Center"
                              HorizontalAlignment="Center"/>
       <ContentPresenter HorizontalAlignment="Center"
                                          VerticalAlignment="Center"/>
      </Grid>
     </Border>
     <ControlTemplate.Triggers>
      <Trigger Property="IsMouseOver" Value="True">
       <Setter TargetName="ButtonBorder" Property="Background"
                                Value="{StaticResource TabItemCloseButtonHoverBackgroundBrush}" />
       <Setter TargetName="ButtonPath" Property="Stroke"
                                Value="{StaticResource TabItemCloseButtonHoverForegroundBrush}"/>
      </Trigger>
      <Trigger Property="IsEnabled" Value="false">
       <Setter Property="Visibility" Value="Collapsed"/>
      </Trigger>
      <Trigger Property="IsPressed" Value="true">
       <Setter TargetName="ButtonBorder"
                                Property="Background"
                                Value="{StaticResource TabItemCloseButtonPressedBackgroundBrush}" />
       <Setter TargetName="ButtonBorder"
                                Property="BorderBrush"
                                Value="{StaticResource TabItemCloseButtonPressedBorderBrush}" />
       <Setter TargetName="ButtonPath" Property="Stroke"
                                Value="{StaticResource TabItemCloseButtonPressedForegroundBrush}"/>

       <Setter TargetName="ButtonPath" Property="Margin" Value="2.5,2.5,1.5,1.5" />
      </Trigger>
     </ControlTemplate.Triggers>
    </ControlTemplate>
   </Setter.Value>
  </Setter>
 </Style>
 <!--关闭按钮相关结束-->


 <!--<SnippetTabControl>-->
 <!--<Snippet13>-->
 <Style TargetType="{x:Type local:ZbTabControl}">
  <Setter Property="SnapsToDevicePixels"
    Value="True" />
  <Setter Property="IsShowCloseTabItemButton" Value="True"></Setter>
  <Setter Property="Template">
   <Setter.Value>
    <ControlTemplate TargetType="{x:Type local:ZbTabControl}">
     <Grid KeyboardNavigation.TabNavigation="Local">
      <Grid.RowDefinitions>
       <RowDefinition Height="Auto" />
       <RowDefinition Height="*" />
      </Grid.RowDefinitions>
      <VisualStateManager.VisualStateGroups>
       <VisualStateGroup x:Name="CommonStates">
        <VisualState x:Name="Disabled">
         <Storyboard>
          <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                   Storyboard.TargetProperty="(Border.BorderBrush).
                      (SolidColorBrush.Color)">
           <EasingColorKeyFrame KeyTime="0"
                 Value="#FFAAAAAA" />
          </ColorAnimationUsingKeyFrames>
         </Storyboard>
        </VisualState>
       </VisualStateGroup>
      </VisualStateManager.VisualStateGroups>
      <TabPanel x:Name="HeaderPanel"
          Grid.Row="0"
          Panel.ZIndex="1"
          Margin="1,0,4,-1"
          IsItemsHost="True"
          KeyboardNavigation.TabIndex="1"
          Background="Transparent">
      </TabPanel>
      <Border x:Name="Border"
        Grid.Row="1"
        BorderThickness="0,2"
        CornerRadius="2"
        KeyboardNavigation.TabNavigation="Local"
        KeyboardNavigation.DirectionalNavigation="Contained"
        KeyboardNavigation.TabIndex="2">
       <Border.Background>
        <LinearGradientBrush EndPoint="0.5,1"
              StartPoint="0.5,0">
         <GradientStop Color="{DynamicResource ContentAreaColorLight}"
              Offset="0" />
         <GradientStop Color="{DynamicResource ContentAreaColorDark}"
              Offset="1" />
        </LinearGradientBrush>
       </Border.Background>
       <Border.BorderBrush>
        <SolidColorBrush Color="{DynamicResource TabItemBorderColor}" />
       </Border.BorderBrush>
       <ContentPresenter x:Name="PART_SelectedContentHost"
             Margin="4"
             ContentSource="SelectedContent" />
      </Border>
     </Grid>
    </ControlTemplate>
   </Setter.Value>
  </Setter>
 </Style>
 <!--</Snippet13>-->

 <Style TargetType="{x:Type local:ZbTabItem}">
  <Setter Property="IsShowCloseTabItemButton"
    Value="{Binding Path=IsShowCloseTabItemButton, RelativeSource={RelativeSource AncestorType=local:ZbTabControl}}">
  </Setter>
  <Setter Property="Template">
   <Setter.Value>
    <ControlTemplate TargetType="{x:Type local:ZbTabItem}">
     <Grid x:Name="Root">
      <Border x:Name="Border"
        Margin="0,0,-4,0"
        BorderThickness="1,1,1,1"
        CornerRadius="4,4,0,0">
       <Border.BorderBrush>
        <LinearGradientBrush StartPoint="0,0"
              EndPoint="0,1">
         <LinearGradientBrush.GradientStops>
          <GradientStopCollection>
           <GradientStop Offset="0.0" />
           <GradientStop Offset="1.0" />
          </GradientStopCollection>
         </LinearGradientBrush.GradientStops>
        </LinearGradientBrush>
       </Border.BorderBrush>
       <Border.Background>
        <LinearGradientBrush StartPoint="0,0"
              EndPoint="0,1">
         <LinearGradientBrush.GradientStops>
          <GradientStopCollection>
           <GradientStop Offset="0.0" />
           <GradientStop Offset="1.0" />
          </GradientStopCollection>
         </LinearGradientBrush.GradientStops>
        </LinearGradientBrush>
       </Border.Background>
       <Grid>
        <Grid.ColumnDefinitions>
         <ColumnDefinition></ColumnDefinition>
         <ColumnDefinition Width="16"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <ContentPresenter x:Name="ContentSite"
              VerticalAlignment="Center"
              HorizontalAlignment="Center"
              ContentSource="Header"
              Margin="4,2"
              RecognizesAccessKey="True" />
        <Button Visibility="Hidden" Grid.Column="1" Name="CloseButton"
          Tag="{TemplateBinding Header}"
          Command="local:ZbTabControl.CloseTabItemCommand"
          CommandParameter="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:ZbTabItem}}}"
          VerticalAlignment="Center" HorizontalAlignment="Left"
          Style="{StaticResource TabItemCloseButtonStyle}">
        </Button>

       </Grid>
      </Border>
      <VisualStateManager.VisualStateGroups>
       <VisualStateGroup x:Name="SelectionStates">
        <VisualState x:Name="Unselected" />
        <VisualState x:Name="Selected">
         <!--<Storyboard>
          <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                   Storyboard.TargetProperty="(Border.Background).
                      (GradientBrush.GradientStops)[1].(GradientStop.Color)">
           <EasingColorKeyFrame KeyTime="0"
                 Value="{StaticResource ControlPressedColor}" />
          </ColorAnimationUsingKeyFrames>
          <ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderThickness)"
                    Storyboard.TargetName="Border">
           <EasingThicknessKeyFrame KeyTime="0"
                  Value="2,2,2,0" />
          </ThicknessAnimationUsingKeyFrames>
         </Storyboard>-->
        </VisualState>
       </VisualStateGroup>
       <VisualStateGroup x:Name="CommonStates">
        <VisualState x:Name="Normal" />
        <VisualState x:Name="MouseOver" />
        <VisualState x:Name="Disabled">
         <Storyboard>
          <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                   Storyboard.TargetProperty="(Panel.Background).
                      (GradientBrush.GradientStops)[1].(GradientStop.Color)">
           <EasingColorKeyFrame KeyTime="0"
                 Value="{StaticResource DisabledControlDarkColor}" />
          </ColorAnimationUsingKeyFrames>
          <ColorAnimationUsingKeyFrames Storyboard.TargetName="Border"
                   Storyboard.TargetProperty="(Border.BorderBrush).
                      (SolidColorBrush.Color)">
           <EasingColorKeyFrame KeyTime="0"
                 Value="{StaticResource DisabledBorderLightColor}" />
          </ColorAnimationUsingKeyFrames>
         </Storyboard>
        </VisualState>
       </VisualStateGroup>
      </VisualStateManager.VisualStateGroups>
     </Grid>
     <ControlTemplate.Triggers>
      <Trigger Property="IsMouseOver"
         Value="True">
       <Setter Property="Background"
         TargetName="Border"
         Value="{StaticResource TabItemFocuseBackground}">
       </Setter>
      </Trigger>
      <Trigger Property="IsSelected"
         Value="True">
       <Setter Property="Panel.ZIndex"
         Value="100" />
       <Setter Property="Background"
         TargetName="Border"
         Value="{StaticResource TabItemSelectedBackground}">
         </Setter>
      </Trigger>
      <MultiTrigger>
       <MultiTrigger.Conditions>
        <Condition Property="IsMouseOver"
         Value="True"></Condition>
        <Condition Property="IsShowCloseTabItemButton"
             Value="True"></Condition>
       </MultiTrigger.Conditions>
       <Setter TargetName="CloseButton" Property="Visibility"
         Value="Visible"></Setter>
      </MultiTrigger>
      <MultiTrigger>
       <MultiTrigger.Conditions>
        <Condition Property="IsSelected"
         Value="True"></Condition>
        <Condition Property="IsShowCloseTabItemButton"
             Value="True"></Condition>
       </MultiTrigger.Conditions>
       <Setter TargetName="CloseButton" Property="Visibility"
         Value="Visible"></Setter>
      </MultiTrigger>
     </ControlTemplate.Triggers>
    </ControlTemplate>
   </Setter.Value>
  </Setter>
 </Style>
 <!--</SnippetTabControl>-->
</ResourceDictionary>

2、ZbTabControl.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 Zbsoft.WpfControls
{
    /// <summary>
    /// 自定义标签控件,支持关闭单个标签页
    /// </summary>
    public class ZbTabControl : TabControl
    {
        /// <summary>
        /// 标签关闭后执行的操作
        /// </summary>
        public event Action<object, ExecutedRoutedEventArgs> Closed;
        /// <summary>
        /// 标签即将关闭时执行的操作
        /// </summary>
        public event System.ComponentModel.CancelEventHandler Closing;

        /// <summary>
        /// 关闭标签命令
        /// </summary>
        private static RoutedUICommand closeTabItemCommand;
        /// <summary>
        /// 是否显示关闭标签按钮
        /// </summary>
        public static DependencyProperty IsShowCloseTabItemButtonProperty;
        /// <summary>
        /// 获取或设置是否显示关闭标签页面的按钮
        /// </summary>
        public bool IsShowCloseTabItemButton
        {
            get { return (bool)GetValue(IsShowCloseTabItemButtonProperty); }
            set { SetValue(IsShowCloseTabItemButtonProperty, value); }
        }

        static ZbTabControl()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ZbTabControl), new FrameworkPropertyMetadata(typeof(ZbTabControl)));
            closeTabItemCommand = new RoutedUICommand("", "CloseTabItemCommand",
                typeof(ZbTabControl));
            IsShowCloseTabItemButtonProperty = DependencyProperty.Register("IsShowCloseTabItemButton",
                typeof(bool), typeof(ZbTabControl));
        }
        /// <summary>
        /// 应用模板时,添加命令到窗口中
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            CommandBinding binding = new CommandBinding(closeTabItemCommand);
            binding.Executed += new ExecutedRoutedEventHandler(binding_Executed);
            binding.CanExecute += new CanExecuteRoutedEventHandler(binding_CanExecute);
            Window w = Window.GetWindow(this);
            if (w != null && !w.CommandBindings.Contains(binding))
                w.CommandBindings.Add(binding);
        }
        /// <summary>
        /// 判断是否允许执行关闭标签操作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void binding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            TabItem item = e.Parameter as TabItem;
            if (item == null)
                return;
            if (item.IsEnabled)
                e.CanExecute = true;
            else
                e.CanExecute = false;
        }
        /// <summary>
        /// 关闭标签页实际执行函数
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void binding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            ZbTabItem item = e.Parameter as ZbTabItem;
            if (item == null)
                return;
            if (Closing != null)
            {
                System.ComponentModel.CancelEventArgs arg = new System.ComponentModel.CancelEventArgs();
                Closing(item, arg);
                if (arg.Cancel)
                    return;
            }
            this.Items.Remove(item);
            if (Closed != null)
            {
                Closed(item, e);
            }
        }
        /// <summary>
        /// 关闭标签命令
        /// </summary>
        public static RoutedUICommand CloseTabItemCommand
        {
            get { return closeTabItemCommand; }
        }
    }
}

3、ZbTabItem.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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 Zbsoft.WpfControls
{
    /// <summary>
    ///
    ///     <MyNamespace:ZbTabItem/>
    ///
    /// </summary>
    public class ZbTabItem : TabItem
    {
        public static DependencyProperty IsShowCloseTabItemButtonProperty;
        /// <summary>
        /// 是否显示关闭标签页面的按钮
        /// </summary>
        public bool IsShowCloseTabItemButton
        {
            get { return (bool)GetValue(IsShowCloseTabItemButtonProperty); }
            set { SetValue(IsShowCloseTabItemButtonProperty, value); }
        }

        static ZbTabItem()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ZbTabItem), new FrameworkPropertyMetadata(typeof(ZbTabItem)));
            IsShowCloseTabItemButtonProperty = DependencyProperty.Register("IsShowCloseTabItemButton",
               typeof(bool), typeof(ZbTabItem));
        }

    }
}

4、例子片断:

  <my:ZbTabControl Grid.Row="1" IsShowCloseTabItemButton="True">
   <my:ZbTabItem Header="我的同事"
        Name="Test"
        HorizontalAlignment="Stretch"
        HorizontalContentAlignment="Stretch"
        VerticalContentAlignment="Stretch">
    <Grid>
     <Grid.RowDefinitions>
      <RowDefinition MinHeight="20" MaxHeight="30"></RowDefinition>
      <RowDefinition></RowDefinition>
     </Grid.RowDefinitions>
     <my:ZbTextBox Name="searchTextBox" Grid.Row="0" BackPromptString="模糊搜索,多个条件以逗号(半角)间隔为并且,空格间隔为或" Margin="5,2" TextChanged="ZbTextBox_TextChanged"></my:ZbTextBox>
     <ScrollViewer Name="MyFriendScroll" Grid.Row="1" VirtualizingStackPanel.IsVirtualizing="False">
      <ListBox BorderThickness="0"
         Name="MyFriendList"
         HorizontalContentAlignment="Stretch"
         AlternationCount="2"
         ItemTemplate="{StaticResource FriendGroup}"
         GotFocus="MyFriendList_Loaded"
         PreviewMouseWheel="MyFriendList_PreviewMouseWheel"
         MouseDoubleClick="MyFriendList_MouseDoubleClick">
      </ListBox>
     </ScrollViewer>
     <ScrollViewer Name="MyFriendScrollSearch" Grid.Row="1" Visibility="Collapsed">
      <ListBox BorderThickness="0"
         Name="MyFriendListSearch"
         HorizontalContentAlignment="Stretch"
         AlternationCount="2"
         ItemTemplate="{StaticResource LogonTemplate}"
         PreviewMouseWheel="MyFriendList_PreviewMouseWheel"
         MouseDoubleClick="MyFriendList_MouseDoubleClick">
      </ListBox>
     </ScrollViewer>
    </Grid>
   </my:ZbTabItem>
......

</my:ZbTabControl>

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值