0
votes

I am trying to create a tabcontrol where tabitems have an image, text and close button and save it as a usercontrol. What I currently have is this image. The XAML code for this is below

Main window

<Window x:Class="TabControlExperiments.MainWindow"
        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:local="clr-namespace:TabControlExperiments"
        mc:Ignorable="d"
        xmlns:uc ="clr-namespace:TabControlExperiments.UserControls"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <TabControl>
            <TabItem>
                <TabItem.Header>
                    <uc:TabHeader Text="This is a new Tab" Image="../Images/ThreeCircles.png"/>
                </TabItem.Header>
            </TabItem>
        </TabControl>
    </Grid>
</Window>

And the TabHeader usercontrol:

<UserControl x:Class="TabControlExperiments.UserControls.TabHeader"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:local="clr-namespace:TabControlExperiments.UserControls"
             mc:Ignorable="d"
             d:DesignHeight="450"
             d:DesignWidth="800">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="20*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Image Grid.Column="0"
               Height="20"
               Source="{Binding Image, RelativeSource={RelativeSource AncestorType={x:Type local:TabHeader}}}" />
        <Label Grid.Column="1"
               Content="{Binding Text, RelativeSource={RelativeSource AncestorType={x:Type local:TabHeader}}}" />
        <Canvas Grid.Column="2"
                Width="12"
                Height="12"
                Background="Transparent"
                MouseDown="Canvas_MouseDown">
            <Path Canvas.Left="2"
                  Canvas.Top="1"
                  Data="M0,0 L10,10 M10,0 L0,10"
                  Stroke="Black"
                  StrokeThickness="2"
                  StrokeEndLineCap="Round" />
        </Canvas>
    </Grid>
</UserControl>

The Canvas_MouseDown event handler removes the tabitem (where the usercontrol resides) from its parent.

As you can see, in this design, I have to explicitly define the header for the tabitem everytime I create the tab either in XAML or in code behind. Is there any way to create a usercontrol for either the tab control or tab item so that when I add it, I can specify the text and image directly? Something like this.

    <TabControl>
        <uc:TabItem Text="This is a new Tab"
                    Image="../Images/ThreeCircles.png">
            <TextBlock />
        </uc:TabItem>
    </TabControl>    

I tried creating custom styles for tab item, but that did not go far as I was not sure how to create the event handler to close the tab.

1

1 Answers

0
votes
  • When you want to use the default tabItem style, you can set both the text and the image for the tabItem.
  • If you are in this situation.You need to define your own tabItem template and add additional attributes to it.

attactedProperty

/// <summary>
/// 附加属性:图标
/// </summary>
public static class AttachedIcon
{
    static readonly Type OwnerType = typeof(AttachedIcon);

    #region Value

    /// <summary>
    /// 获取或设置 <see cref="DependencyObject"/> 的附加图标
    /// </summary>
    public static readonly DependencyProperty ValueProperty = DependencyProperty.RegisterAttached("Value", typeof(object), OwnerType, new PropertyMetadata(default(object)));

    /// <summary>
    /// 设置 <see cref="DependencyObject"/> 的 <see cref="ValueProperty"/> 属性值
    /// </summary>
    /// <param name="element"></param>
    /// <param name="value"></param>
    public static void SetValue(DependencyObject element, object value)
    {
        element.SetValue(ValueProperty, value);
    }

    /// <summary>
    /// 获取 <see cref="DependencyObject"/> 的 <see cref="ValueProperty"/> 属性值
    /// </summary>
    /// <param name="element"></param>
    /// <returns></returns>
    public static object GetValue(DependencyObject element)
    {
        return (object) element.GetValue(ValueProperty);
    }

    #endregion
}

xaml.cs

<ControlTemplate TargetType="{x:Type TabItem}">
                <Border x:Name="Border" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
                    <StackPanel 
                        Orientation="Horizontal" Focusable="False" 
                        HorizontalAlignment="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" 
                        Margin="{TemplateBinding Padding}" 
                        SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                        VerticalAlignment="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}">
                        <Image x:Name="IconPresenter" Source="{TemplateBinding i:AttachedIcon.Value}"></Image>
                        <ContentPresenter x:Name="ContentPresenter" ContentSource="Header" RecognizesAccessKey="True" />
                    </StackPanel>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter TargetName="Border" Property="BorderBrush" Value="{StaticResource PrimaryBrush}"/>
                        <Setter TargetName="ContentPresenter" Property="TextElement.Foreground" Value="{StaticResource PrimaryBrush}"/>
                    </Trigger>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabControl}},Path=TabStripPlacement}" Value="{x:Static Dock.Top}">
                        <Setter TargetName="Border" Property="BorderThickness" Value="0,0,0,3"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabControl}},Path=TabStripPlacement}" Value="{x:Static Dock.Left}">
                        <Setter TargetName="Border" Property="BorderThickness" Value="0,0,3,0"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabControl}},Path=TabStripPlacement}" Value="{x:Static Dock.Right}">
                        <Setter TargetName="Border" Property="BorderThickness" Value="3,0,0,0"/>
                    </DataTrigger>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type TabControl}},Path=TabStripPlacement}" Value="{x:Static Dock.Bottom}">
                        <Setter TargetName="Border" Property="BorderThickness" Value="0,3,0,0"/>
                    </DataTrigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>