Как создать пользовательский пользовательский элемент управления на основе элемента управления tab, чтобы элементы tab имели определенный формат

#c# #wpf #user-controls

#c# #wpf #пользовательские элементы управления

Вопрос:

Я пытаюсь создать tabcontrol, где tabitems имеют изображение, текст и кнопку закрытия и сохраняют его как usercontrol. То, что у меня сейчас есть, — это этот образ. Код XAML для этого приведен ниже

Главное окно

 <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>
 

И пользовательский контроль в заголовке табуляции:

 <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>
 

Обработчик события Canvas_MouseDown удаляет tabitem (где находится usercontrol) из его родительского элемента.

Как вы можете видеть, в этом проекте я должен явно определять заголовок для элемента tabitem каждый раз, когда я создаю вкладку либо в XAML, либо в коде. Есть ли какой-нибудь способ создать пользовательский элемент управления для элемента управления tab или элемента tab, чтобы при его добавлении я мог напрямую указывать текст и изображение? Что-то вроде этого.

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

Я попытался создать пользовательские стили для элемента вкладки, но это не помогло, так как я не был уверен, как создать обработчик событий для закрытия вкладки.

Ответ №1:

  • Если вы хотите использовать стиль TabItem по умолчанию, вы можете задать как текст, так и изображение для TabItem.
  • Если вы находитесь в этой ситуации.Вам нужно определить свой собственный шаблон TabItem и добавить к нему дополнительные атрибуты.

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>