wpf 自定义 TabControl [英] wpf custom TabControl

查看:40
本文介绍了wpf 自定义 TabControl的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我真的只想要一个 TabControl,它具有可关闭的自定义 TabItems,基于来自 这里.

I really just want a TabControl that has custom TabItems that are closable, based on code from here.

我认为这个问题和我的一样,但是代码 &下面的 xaml 留下空标签.

I thought that this question was the same as mine, but the combination of code & xaml below leaves empty tabs.

public class ClosableTabControl : TabControl
{
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new ClosableTabItem();
    }
}

        <uc:ClosableTabControl x:Name="Items" Grid.Column="1">
            <uc:ClosableTabControl.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding DisplayName}" />
                </DataTemplate>
            </uc:ClosableTabControl.ItemTemplate>
            <uc:ClosableTabControl.ContentTemplate>
                <DataTemplate>
                    <ContentControl>
                        <local:EmpView DataContext="{Binding ., Mode=TwoWay}"/>
                    </ContentControl>
                </DataTemplate>
            </uc:ClosableTabControl.ContentTemplate>
        </uc:ClosableTabControl>

xaml 适用于 TabControl(而不是 uc:ClosableTabControl).

The xaml works on a TabControl (instead of uc:ClosableTabControl).

让 TabControl 为儿童提供 ClosableTabItems 的最佳方法是什么?

What is the best way to have a TabControl that has ClosableTabItems for children?

干杯,
贝瑞尔

附言我会发布 ClosableTabItem 的代码,但我想在第一篇文章中降低噪音水平.如果有帮助,请让我发布.

p.s. I would post the code for the ClosableTabItem but I wanted to keep the noise level down on the first post. Ask me to post it if it will help.

推荐答案

这是我的 TabControl 的截图:

Here is a screenshot of my TabControl:

首先,关闭按钮是一个自定义控件,允许为悬停和按下状态使用不同的颜色.

First of all, the close button is a custom control that allows to use different colors for Hover and Pressed states.

Add -> New Item -> Custom Control -> GlyphButton

GlyphButton.cs

public class GlyphButton : Button
{
    public static readonly DependencyProperty GlyphForegroundProperty = DependencyProperty.Register("GlyphForeground", typeof(Brush), typeof(GlyphButton));
    public static readonly DependencyProperty HoverBackgroundProperty = DependencyProperty.Register("HoverBackground", typeof(Brush), typeof(GlyphButton));
    public static readonly DependencyProperty HoverBorderBrushProperty = DependencyProperty.Register("HoverBorderBrush", typeof(Brush), typeof(GlyphButton));
    public static readonly DependencyProperty HoverBorderThicknessProperty = DependencyProperty.Register("HoverBorderThickness", typeof(Thickness), typeof(GlyphButton));
    public static readonly DependencyProperty HoverForegroundProperty = DependencyProperty.Register("HoverForeground", typeof(Brush), typeof(GlyphButton));
    public static readonly DependencyProperty PressedBackgroundProperty = DependencyProperty.Register("PressedBackground", typeof(Brush), typeof(GlyphButton));
    public static readonly DependencyProperty PressedBorderBrushProperty = DependencyProperty.Register("PressedBorderBrush", typeof(Brush), typeof(GlyphButton));
    public static readonly DependencyProperty PressedBorderThicknessProperty = DependencyProperty.Register("PressedBorderThickness", typeof(Thickness), typeof(GlyphButton));
    public static readonly DependencyProperty PressedForegroundProperty = DependencyProperty.Register("PressedForeground", typeof(Brush), typeof(GlyphButton));

    static GlyphButton()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(GlyphButton), new FrameworkPropertyMetadata(typeof(GlyphButton)));
    }

    public Brush GlyphForeground
    {
        get
        {
            return (Brush)base.GetValue(GlyphForegroundProperty);
        }
        set
        {
            base.SetValue(GlyphForegroundProperty, value);
        }
    }

    public Brush HoverBackground
    {
        get
        {
            return (Brush)base.GetValue(HoverBackgroundProperty);
        }
        set
        {
            base.SetValue(HoverBackgroundProperty, value);
        }
    }

    public Brush HoverBorderBrush
    {
        get
        {
            return (Brush)base.GetValue(HoverBorderBrushProperty);
        }
        set
        {
            base.SetValue(HoverBorderBrushProperty, value);
        }
    }

    public Thickness HoverBorderThickness
    {
        get
        {
            return (Thickness)base.GetValue(HoverBorderThicknessProperty);
        }
        set
        {
            base.SetValue(HoverBorderThicknessProperty, value);
        }
    }

    public Brush HoverForeground
    {
        get
        {
            return (Brush)base.GetValue(HoverForegroundProperty);
        }
        set
        {
            base.SetValue(HoverForegroundProperty, value);
        }
    }

    public Brush PressedBackground
    {
        get
        {
            return (Brush)base.GetValue(PressedBackgroundProperty);
        }
        set
        {
            base.SetValue(PressedBackgroundProperty, value);
        }
    }

    public Brush PressedBorderBrush
    {
        get
        {
            return (Brush)base.GetValue(PressedBorderBrushProperty);
        }
        set
        {
            base.SetValue(PressedBorderBrushProperty, value);
        }
    }

    public Thickness PressedBorderThickness
    {
        get
        {
            return (Thickness)base.GetValue(PressedBorderThicknessProperty);
        }
        set
        {
            base.SetValue(PressedBorderThicknessProperty, value);
        }
    }

    public Brush PressedForeground
    {
        get
        {
            return (Brush)base.GetValue(PressedForegroundProperty);
        }
        set
        {
            base.SetValue(PressedForegroundProperty, value);
        }
    }
}

主题/Generic.xaml

<Style TargetType="{x:Type local:GlyphButton}">
    <Setter Property="Width" Value="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}" />
    <Setter Property="Foreground" Value="{Binding Path=GlyphForeground, RelativeSource={RelativeSource Self}}" />
    <Setter Property="Background" Value="Transparent" />
    <Setter Property="BorderBrush" Value="Transparent" />
    <Setter Property="BorderThickness" Value="1" />
    <Setter Property="Focusable" Value="false" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:GlyphButton}">
                <Border Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
                    <ContentPresenter />
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="true">
                        <Setter TargetName="Border" Value="{Binding HoverBackground , RelativeSource={RelativeSource TemplatedParent}}" Property="Background" />
                        <Setter TargetName="Border" Value="{Binding HoverBorderBrush , RelativeSource={RelativeSource TemplatedParent}}" Property="BorderBrush" />
                        <Setter TargetName="Border" Value="{Binding HoverBorderThickness , RelativeSource={RelativeSource TemplatedParent}}" Property="BorderThickness" />
                        <Setter Value="{Binding HoverForeground , RelativeSource={RelativeSource TemplatedParent}}" Property="Foreground" />
                    </Trigger>
                    <Trigger Property="IsPressed" Value="True">
                        <Setter TargetName="Border" Value="{Binding PressedBackground , RelativeSource={RelativeSource TemplatedParent}}" Property="Background" />
                        <Setter TargetName="Border" Value="{Binding PressedBorderBrush , RelativeSource={RelativeSource TemplatedParent}}" Property="BorderBrush" />
                        <Setter TargetName="Border" Value="{Binding PressedBorderThickness , RelativeSource={RelativeSource TemplatedParent}}" Property="BorderThickness" />
                        <Setter Value="{Binding PressedForeground , RelativeSource={RelativeSource TemplatedParent}}" Property="Foreground" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

TabItem 的样式.您可以将其放在 App.xaml 或资源字典中的任何位置.

Style for a TabItem. You can put it anywhere, in App.xaml or in a resource dictionary.

TabItem 样式

<SolidColorBrush x:Key="FileTabTextKey" Color="#ffffff"/>

<SolidColorBrush x:Key="ToolWindowButtonHoverActiveKey" Color="#fffcf4"/>
<SolidColorBrush x:Key="ToolWindowButtonHoverActiveBorderKey" Color="#e5c365"/>
<SolidColorBrush x:Key="ToolWindowButtonHoverActiveGlyphKey" Color="#000000"/>
<SolidColorBrush x:Key="ToolWindowButtonDownKey" Color="#ffe8a6"/>
<SolidColorBrush x:Key="ToolWindowButtonDownBorderKey" Color="#e5c365"/>
<SolidColorBrush x:Key="ToolWindowButtonDownActiveGlyphKey" Color="#000000"/>

<LinearGradientBrush x:Key="FileTabHotGradientKey">
    <GradientStop Color="#707776"/>
    <GradientStop Color="#4b5c74"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="FileTabHotBorderKey" Color="#9ba7b7"/>
<SolidColorBrush x:Key="FileTabHotTextKey" Color="#ffffff"/>
<SolidColorBrush x:Key="FileTabHotGlyphKey" Color="#ced4dd"/>

<LinearGradientBrush x:Key="FileTabSelectedGradientKey" StartPoint="0.5,0" EndPoint="0.5,1">
    <GradientStop Color="#fffcf4"/>
    <GradientStop Color="#fff3cd" Offset="0.5"/>
    <GradientStop Color="#ffe8a6" Offset="0.5"/>
    <GradientStop Color="#ffe8a6" Offset="1"/>
</LinearGradientBrush>
<SolidColorBrush x:Key="FileTabSelectedTextKey" Color="#000000"/>
<SolidColorBrush x:Key="FileTabSelectedGlyphKey" Color="#75633d"/>

<Style x:Key="OrangeTabItem" TargetType="{x:Type TabItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type TabItem}">
                <Border AllowDrop="true" ToolTip="{Binding Title}">
                    <Border Name="Border" Background="Transparent" BorderBrush="Transparent" BorderThickness="1,1,1,0" CornerRadius="2,2,0,0">
                        <DockPanel x:Name="TitlePanel" TextElement.Foreground="{StaticResource FileTabTextKey}">
                            <controls:GlyphButton x:Name="HideButton" 
                            DockPanel.Dock="Right" 
                            GlyphForeground="Transparent" 
                            HoverBackground="{StaticResource ToolWindowButtonHoverActiveKey}" 
                            HoverBorderBrush="{StaticResource ToolWindowButtonHoverActiveBorderKey}" 
                            HoverForeground="{StaticResource ToolWindowButtonHoverActiveGlyphKey}" 
                            PressedBackground="{StaticResource ToolWindowButtonDownKey}" 
                            PressedBorderBrush="{StaticResource ToolWindowButtonDownBorderKey}" 
                            PressedForeground="{StaticResource ToolWindowButtonDownActiveGlyphKey}"
                            HoverBorderThickness="1" PressedBorderThickness="1" Margin="3,2,3,4" 
                            Command="{Binding RequestCloseCommand}"
                            CommandParameter="{Binding}"
                            ToolTip="Close">
                                <Path x:Name="CloseButtonStroke" Width="10" Height="8" Stretch="Uniform" Data="F1 M 0,0 L 2,0 5,3 8,0 10,0 6,4 10,8 8,8 5,5 2,8 0,8 4,4 0,0 Z" 
                                Fill="{Binding Path=(TextElement.Foreground), RelativeSource={RelativeSource Self}}" />
                            </controls:GlyphButton>

                            <ContentPresenter x:Name="Content" HorizontalAlignment="Stretch" Margin="4,2,4,4" VerticalAlignment="Stretch" RecognizesAccessKey="true" ContentSource="Header" />
                        </DockPanel>
                    </Border>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="true">
                        <Setter TargetName="Border" Value="{StaticResource FileTabHotGradientKey}" Property="Background" />
                        <Setter TargetName="Border" Value="{StaticResource FileTabHotBorderKey}" Property="BorderBrush" />
                        <Setter TargetName="TitlePanel" Value="{StaticResource FileTabHotTextKey}" Property="TextElement.Foreground" />
                        <Setter TargetName="HideButton" Value="{StaticResource FileTabHotGlyphKey}" Property="GlyphForeground" />
                    </Trigger>
                    <Trigger Property="IsSelected" Value="True">
                        <Setter Property="Panel.ZIndex" Value="1" />
                        <Setter TargetName="Border" Value="{StaticResource FileTabSelectedGradientKey}" Property="Background" />
                        <Setter TargetName="Border" Value="{StaticResource FileTabSelectedGradientKey}" Property="BorderBrush" />
                        <Setter TargetName="Border" Property="BorderThickness" Value="0" />
                        <Setter TargetName="Border" Property="Padding" Value="0,1,0,0" />
                        <Setter TargetName="HideButton" Property="Margin" Value="3" />
                        <Setter TargetName="TitlePanel" Value="{StaticResource FileTabSelectedTextKey}" Property="TextElement.Foreground" />
                        <Setter TargetName="HideButton" Value="{StaticResource FileTabSelectedGlyphKey}" Property="GlyphForeground" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

现在是主窗口.我的 TabControl 需要蓝色背景,但您可以根据需要更改颜色.

Now the Main Window. My TabControl requires a blue background, but you can change the colors if you want.

    <Grid Background="#FF293955">
    <TabControl ItemsSource="{Binding Items}" ItemContainerStyle="{StaticResource OrangeTabItem}">
        <TabControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding Title}"/>
            </DataTemplate>
        </TabControl.ItemTemplate>
        <TabControl.ContentTemplate>
            <DataTemplate>
                <ContentControl Content="{Binding Content}"/>
            </DataTemplate>
        </TabControl.ContentTemplate>
    </TabControl>
</Grid>

最后一个重要说明:表示 TabItem 的模型必须包含命令 RequestCloseCommand

And finally one important remark: a model that represents TabItem must contain the command RequestCloseCommand

两个ViewModels

public class MainViewModel
{
    public MainViewModel()
    {
        this.Items = new ObservableCollection<TabItemViewModel>
                     {
                         new TabItemViewModel("Tab 1", OnItemRequestClose),
                         new TabItemViewModel("Tab item 2", OnItemRequestClose)
                     };
    }

    public ObservableCollection<TabItemViewModel> Items { get; set; }

    public void OnItemRequestClose(TabItemViewModel item)
    {
        this.Items.Remove(item);
    }
}

public class TabItemViewModel
{
    public TabItemViewModel(string title, Action<TabItemViewModel> onClose)
    {
        this.Title = title;
        this.RequestCloseCommand = new SimpleCommand(obj => onClose(this));
        this.Content = "Test content " + title;
    }

    public string Title { get; set; }

    public ICommand RequestCloseCommand { get; set; }

    public object Content { get; set; }
}

我考虑过使用 RoutedUICommand 但修改这种类型的命令需要很多时间.所以这个方案现在最适合我.

I thought about using RoutedUICommand but it will take much time to revise this type of commands. So this solution is the most appropriate for me now.

这篇关于wpf 自定义 TabControl的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆