silverlight中创建自定义的Tabcontrol控件
silverlight的SDK中已经提供了一个Tabcontrol 控件,但是在实际开发中还有很多问题需要修改。
问题1:TabItem没有关闭按钮。
问题2:TabItem的数量太多导致宽度超出的时候会换行显示
所以我们需要创建一个自己的Tabcontrol控件,既然SDK中已经实现了大部分功能,我们就在它的基础上修改下就好。
废话不多说,先看效果
根据Sdk里面的源码重新控件主要分为两部分,即TabItem部分和Tabcontrol部分。
下面是TabItem部分XAML的关键代码:
<Grid x:Name="TemplateTopSelected" Visibility="Collapsed" Canvas.ZIndex="1">
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1,1,1,0" Background="{TemplateBinding Background}" Margin="-2,-2,-2,0" CornerRadius="3,3,0,0">
<Border BorderThickness="1" BorderBrush="#FFFFFFFF" CornerRadius="1,1,0,0">
<Border.Background>
<LinearGradientBrush StartPoint=".7,0" EndPoint=".7,1">
<GradientStop Color="#FFFFFFFF" Offset="0" />
<GradientStop Color="#F9FFFFFF" Offset="0.375" />
<GradientStop Color="#E5FFFFFF" Offset="0.625" />
<GradientStop Color="#C6FFFFFF" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<Grid>
<Rectangle Fill="#FFFFFFFF" Margin="0,0,0,-2" />
<StackPanel Orientation="Horizontal">
<ContentControl x:Name="HeaderTopSelected" VerticalAlignment="Center" IsTabStop="False" Foreground="{TemplateBinding Foreground}" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" Margin="{TemplateBinding Padding}" Cursor="{TemplateBinding Cursor}" />
<Border VerticalAlignment="Center" HorizontalAlignment="Right">
<Button Content="X" Width="18" Height="18" FontSize="12" Margin="3,0,0,0" Style="{StaticResource closeButtonStyle}" x:Name="Button1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Background="Transparent">
</Button>
</Border>
</StackPanel>
</Grid>
</Border>
</Border>
<!--Focus Visual-->
<Border x:Name="FocusVisualTop" CornerRadius="3,3,0,0" BorderBrush="#FF6DBDD1" BorderThickness="1,1,1,0" Margin="-2,-2,-2,0" Visibility="Collapsed" IsHitTestVisible="false" />
<Border Margin="-2,-2,-2,0" x:Name="DisabledVisualTopSelected" IsHitTestVisible="false" Opacity="0" Background="#8CFFFFFF" CornerRadius="3,3,0,0" />
</Grid>
<!-- TabStripPlacement Top | Unselected -->
<Grid x:Name="TemplateTopUnselected" Visibility="Collapsed">
<Border x:Name="BorderTop" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="1" Background="{TemplateBinding Background}" CornerRadius="3,3,0,0">
<Border x:Name="GradientTop" BorderThickness="1" BorderBrush="#FFFFFFFF" CornerRadius="1,1,0,0">
<Border.Background>
<LinearGradientBrush StartPoint=".7,0" EndPoint=".7,1">
<GradientStop Color="#FFFFFFFF" Offset="0" />
<GradientStop Color="#F9FFFFFF" Offset="0.375" />
<GradientStop Color="#E5FFFFFF" Offset="0.625" />
<GradientStop Color="#C6FFFFFF" Offset="1" />
</LinearGradientBrush>
</Border.Background>
<Grid>
<StackPanel Orientation="Horizontal">
<ContentControl x:Name="HeaderTopUnselected" IsTabStop="False" Foreground="{TemplateBinding Foreground}" FontSize="{TemplateBinding FontSize}" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" Margin="{TemplateBinding Padding}" Cursor="{TemplateBinding Cursor}" />
<Border Height="18" Width="18" VerticalAlignment="Center" Margin="3,0,3,0" HorizontalAlignment="Right">
<Button Content="X" Style="{StaticResource closeButtonStyle}" x:Name="Button2" VerticalAlignment="Stretch" Visibility="Collapsed" HorizontalAlignment="Stretch" Background="Transparent">
</Button>
</Border>
</StackPanel>
</Grid>
</Border>
</Border>
<Border x:Name="DisabledVisualTopUnSelected" IsHitTestVisible="false" Opacity="0" Background="#8CFFFFFF" CornerRadius="3,3,0,0" />
</Grid>
下面是TabItem部分 CS 的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace Eos.EosControl
{
[TemplatePart(Name = "Button1", Type = typeof(Button))]
[TemplatePart(Name = "Button2", Type = typeof(Button))]
public class EosTabItem : TabItem
{
private static Button CloseButton;
private static Button CloseButton1;
public EosTabItem()
{
this.DefaultStyleKey = typeof(EosTabItem);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
CloseButton = (GetTemplateChild("Button1") as Button);
CloseButton1 = (GetTemplateChild("Button2") as Button);
if (CloseButton != null && CloseButton1 != null)
{
CloseButton.Click += new RoutedEventHandler(CloseButton_Click);
CloseButton1.Click += new RoutedEventHandler(CloseButton_Click);
this.MouseEnter+=new MouseEventHandler(EosTabItem_MouseEnter);
this.MouseLeave+=new MouseEventHandler(EosTabItem_MouseLeave);
}
}
void CloseButton_Click(object sender, RoutedEventArgs e)
{
if (this.Parent as EosTabControl != null)
{
if ((this.Parent as EosTabControl).Items.Count > 1)
{
(this.Parent as EosTabControl).Items.Remove(this);
}
}
else if(this.Parent as TabControl!=null)
{
if ((this.Parent as TabControl).Items.Count > 1)
{
(this.Parent as TabControl).Items.Remove(this);
}
}
}
void EosTabItem_MouseLeave(object sender, MouseEventArgs e)
{
CloseButton1 = (GetTemplateChild("Button2") as Button);
CloseButton1.Visibility = Visibility.Collapsed;
}
void EosTabItem_MouseEnter(object sender, MouseEventArgs e)
{
CloseButton1 = (GetTemplateChild("Button2") as Button);
CloseButton1.Visibility = Visibility.Visible;
}
}
}
下面是TabControl部分 XAML 的关键代码:
<!-- TabStripPlacement Top -->
<Grid x:Name="TemplateTop" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid>
<StackPanel Orientation="Horizontal" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Canvas.ZIndex="1">
<controlsPrimitives:TabPanel x:Name="TabPanelTop" Margin="2,2,2,-1">
</controlsPrimitives:TabPanel>
</StackPanel>
<StackPanel VerticalAlignment="Bottom" >
<Button x:Name="btnShowList" HorizontalAlignment="Right" Content="/EosControl;component/Images/ico1.jpg" Height="20">
<Button.Template>
<ControlTemplate TargetType="Button">
<Image Source="{TemplateBinding Content}" x:Name="btnImg"></Image>
</ControlTemplate>
</Button.Template>
</Button>
<Popup Width="auto" Height="auto" x:Name="HeadList" IsOpen="False">
</Popup>
</StackPanel>
</Grid>
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Grid.Row="1" MinHeight="10" MinWidth="10" CornerRadius="0,0,3,3">
<ContentPresenter x:Name="ContentTop" HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}" Margin="{TemplateBinding Padding}" Cursor="{TemplateBinding Cursor}" />
</Border>
<Border x:Name="DisabledVisualTop" IsHitTestVisible="False" Opacity="0" Canvas.ZIndex="1" Background="#8CFFFFFF" Grid.RowSpan="2" CornerRadius="0,0,3,3" Grid.Row="1" />
</Grid>
下面是TabControl部分 CS 的代码:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Controls.Primitives;
using System.Windows.Media.Imaging;
namespace Eos.EosControl
{
[TemplatePart(Name = "btnShowList", Type = typeof(Button))]
[TemplatePart(Name = "TabPanelTop", Type = typeof(TabPanel))]
[TemplatePart(Name = "HeadList", Type = typeof(TabPanel))]
public class EosTabControl : TabControl
{
private static Button btnShowList;
private static TabPanel itemPanel;
private static Popup HeadList;
public EosTabControl()
{
this.DefaultStyleKey = typeof(EosTabControl);
}
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
btnShowList = (GetTemplateChild("btnShowList") as Button);
itemPanel = (GetTemplateChild("TabPanelTop") as TabPanel);
HeadList = (GetTemplateChild("HeadList") as Popup);
btnShowList.Click += new RoutedEventHandler(btnShowList_Click);
this.SizeChanged += new SizeChangedEventHandler(EosTabControl_SizeChanged);
itemPanel.SizeChanged += new SizeChangedEventHandler(itemPanel_SizeChanged);
btnShowList.LostFocus += new RoutedEventHandler(btnShowList_LostFocus);
btnShowList.MouseEnter += new MouseEventHandler(btnShowList_MouseEnter);
btnShowList.MouseLeave += new MouseEventHandler(btnShowList_MouseLeave);
this.MouseLeftButtonDown += new MouseButtonEventHandler(EosTabControl_MouseLeftButtonDown);
}
void btnShowList_MouseLeave(object sender, MouseEventArgs e)
{
if (HeadList.IsOpen == false)
{
btnShowList.Content = "/EosControl;component/Images/ico1.jpg";
}
}
void btnShowList_MouseEnter(object sender, MouseEventArgs e)
{
if (HeadList.IsOpen == false)
{
btnShowList.Content = "/EosControl;component/Images/ico3.jpg";
}
}
void EosTabControl_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
(this.SelectedItem as TabItem).Focus();
}
void btnShowList_LostFocus(object sender, RoutedEventArgs e)
{
HeadList.IsOpen = false;
btnShowList.Content = "/EosControl;component/Images/ico1.jpg";
}
void btnShowList_Click(object sender, RoutedEventArgs e)
{
if (HeadList.IsOpen == false)
{
double maxWidth = 0;
ListBox headContent = new ListBox();
headContent.BorderThickness = new Thickness(3);
foreach (TabItem eosItem in itemPanel.Children)
{
headContent.Items.Add(eosItem.Header);
if (eosItem.ActualWidth > maxWidth)
{
maxWidth = eosItem.ActualWidth;
}
}
headContent.SelectionChanged += new SelectionChangedEventHandler(headContent_SelectionChanged);
HeadList.Child = headContent;
HeadList.HorizontalOffset = this.ActualWidth - maxWidth + 24;
HeadList.VerticalOffset = 0;
HeadList.IsOpen = true;
btnShowList.Content = "/EosControl;component/Images/ico2.jpg";
}
else
{
(this.SelectedItem as TabItem).Focus();
}
}
void EosTabControl_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (this.ActualWidth > 0)
{
double maxWidth = this.ActualWidth;
double itemsWidth = 30;
double itemMaxWidth = 0;
foreach (TabItem eosItem in itemPanel.Children)
{
itemsWidth += eosItem.ActualWidth;
if (eosItem.ActualWidth > itemMaxWidth)
{
itemMaxWidth = eosItem.ActualWidth;
}
if (itemsWidth < maxWidth)
{
eosItem.Visibility = Visibility.Visible;
}
else
{
eosItem.Visibility = Visibility.Collapsed;
}
}
if (itemPanel.Children[0].Visibility == Visibility.Collapsed)
{
(itemPanel.Children[0] as TabItem).Width = maxWidth - 40;
itemPanel.Children[0].Visibility = Visibility.Visible;
}
HeadList.HorizontalOffset = this.ActualWidth - itemMaxWidth + 24;
}
}
void itemPanel_SizeChanged(object sender, SizeChangedEventArgs e)
{
if (this.ActualWidth > 0)
{
double maxWidth = this.ActualWidth;
double itemsWidth = 30;
double itemMaxWidth = 0;
foreach (TabItem eosItem in itemPanel.Children)
{
itemsWidth += eosItem.ActualWidth;
if (eosItem.ActualWidth > itemMaxWidth)
{
itemMaxWidth = eosItem.ActualWidth;
}
if (itemsWidth < maxWidth)
{
eosItem.Visibility = Visibility.Visible;
}
else
{
eosItem.Visibility = Visibility.Collapsed;
}
}
if (itemPanel.Children[0].Visibility == Visibility.Collapsed)
{
(itemPanel.Children[0] as TabItem).Width = maxWidth - 40;
itemPanel.Children[0].Visibility = Visibility.Visible;
}
HeadList.HorizontalOffset = this.ActualWidth - itemMaxWidth + 24;
}
}
void headContent_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (TabItem eosItem in itemPanel.Children)
{
if (this.Items.IndexOf(eosItem) == (sender as ListBox).SelectedIndex)
{
if (eosItem.Visibility == Visibility.Collapsed)
{
eosItem.Visibility = Visibility.Visible;
this.Items.Remove(eosItem);
this.Items.Insert(0, eosItem);
this.SelectedIndex = 0;
break;
}
else
{
this.SelectedIndex = this.Items.IndexOf(eosItem);
break;
}
}
}
HeadList.IsOpen = false;
(this.SelectedItem as TabItem).Focus();
this.UpdateLayout();
}
}
}
下面是关闭按钮样式 XAML:
<Style TargetType="Button" x:Key="closeButtonStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="RootElement" BorderThickness="1">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimation Duration="0" Storyboard.TargetName="BorderBrush"
Storyboard.TargetProperty="Color" To="#ccc" />
<ColorAnimation Duration="0" Storyboard.TargetName="BorderBrush2"
Storyboard.TargetProperty="Color" To="Black" />
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed" />
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused">
</VisualState>
<VisualState x:Name="Unfocused">
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border.Background>
<SolidColorBrush x:Name="BorderBrush" Color="{TemplateBinding Background}"/>
</Border.Background>
<Border.BorderBrush>
<SolidColorBrush x:Name="BorderBrush2" Color="{TemplateBinding BorderBrush}"></SolidColorBrush>
</Border.BorderBrush>
<Grid Background="{TemplateBinding Background}">
<ContentPresenter
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
此段代码还有不完善的地方,希望高手指点下。
源码下载