如何为 WPF 中的选项卡控件提供自定义形状?
How to give a custom shape to a Tab Control in WPF?
我在 WPF 中创建了一个应用程序,我需要使用 TabControl 在内容之间切换。但由于设计目的,我的 Tab 项目的内容在同一水平线上,然后是 Tab 项目 header.
这是我的 Mainwindow.xaml
的代码
<Grid Width="635" HorizontalAlignment="Left" Height="458" VerticalAlignment="Top" Margin="0,61,0,0" >
<TabControl Margin="-1" BorderThickness="0" Background="#222222" >
<TabItem Style="{StaticResource TabItemDefaults}" Header="File manager" FontSize="10" Foreground="#efefef" Margin="5,0,0,0" Width="97" Height="20" FontFamily="Segoe UI" UseLayoutRounding="True" TextOptions.TextFormattingMode="Display" >
<Grid>
<Label Name="Folder" Content="Folder:" FontSize="10" Foreground="#efefef" Height="20" Width="40" Margin="-571,-367,0,0" FontFamily="Segoe UI" UseLayoutRounding="True" TextOptions.TextFormattingMode="Display" />
<Button Name ="FolderSelect" Width="532" HorizontalAlignment="Left" VerticalAlignment="Top" Height="33" Margin="85,17,0,0" Background="#1a1a1a"
materialDesign:ShadowAssist.ShadowDepth="Depth0" materialDesign:RippleAssist.Feedback="Transparent" BorderThickness="0" UseLayoutRounding="True"
></Button>
<Label Name="ShowFolders" Content=".." Margin="-479,59,0,0" Background="#1a1a1a" Width="168" Height="373" Foreground="#efefef" ></Label>
<Button
Style="{StaticResource MaterialDesignRaisedButton}"
Width="65" HorizontalAlignment="Left" Height="25" Background="#FF403D3D" Margin="16,292,0,0"
ToolTip="Resource name: MaterialDesignRaisedButton">
<materialDesign:PackIcon Kind="PlusThick" />
</Button>
<Button
Style="{StaticResource MaterialDesignRaisedButton}"
Width="65" HorizontalAlignment="Left" Height="25" Background="#FF403D3D" Margin="82,292,0,0"
ToolTip="Open output folder">
<materialDesign:PackIcon Kind="FolderUpload" />
</Button>
<Label Content="Video recordings:" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="269.2,-22,0,0" Foreground="#efefef" FontSize="10" FontFamily="Segoe UI" UseLayoutRounding="True" TextOptions.TextFormattingMode="Display" />
</Grid>
</TabItem>
<TabItem Style="{StaticResource TabItemDefaults}" Header ="Preview" FontSize="10" Foreground="#efefef" Width="67" Height="20" Margin="-8,0,0,0" FontFamily="Segoe UI" UseLayoutRounding="True" TextOptions.TextFormattingMode="Display" >
<Grid>
<CheckBox Content="Draggable mode" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="520,-22,0,0" Width="110" />
</Grid>
</TabItem>
</TabControl>
</Grid>
选项卡控件和选项卡项都是由我在 App.xaml 中声明的控件模板制作的。
这里是我在App.xaml-
中单独声明的Tab Control的代码
<Style TargetType="{x:Type TabControl}" x:Key="TabControlDefaults" x:Name="NewTabcontrol" >
<Setter Property="OverridesDefaultStyle"
Value="True" />
<Setter Property="SnapsToDevicePixels"
Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<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="0,0,4,-1"
IsItemsHost="True"
KeyboardNavigation.TabIndex="1"
Background="Transparent" />
<Border x:Name="Border"
Grid.Row="1"
BorderThickness="1"
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 BorderMediumColor}"/>
</Border.BorderBrush>
<ContentPresenter x:Name="PART_SelectedContentHost"
Margin="4"
ContentSource="SelectedContent" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
这里是我在App.xaml-
中单独声明的Tab Items的代码
<Style TargetType="{x:Type TabItem}" x:Key="TabItemDefaults" x:Name="NewTabitem" >
<Setter Property="Foreground" Value="#bababa" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid x:Name="Panel" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local" >
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="10,2"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Black"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<!-- <Setter TargetName="Panel" Property="Background" Value="LightSkyBlue" /> -->
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{TemplateBinding Content}">
<TextBlock.TextDecorations>
<TextDecoration PenOffset="4" PenOffsetUnit="Pixel" >
<TextDecoration.Pen>
<Pen Brush="#673ab7" Thickness="4" />
</TextDecoration.Pen>
</TextDecoration>
</TextBlock.TextDecorations>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Panel" Property="Background" Value="#212121" />
<Setter Property="Foreground" Value="WhiteSmoke"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
我的问题是复选框(我给了一个红色圆圈)不能正常工作。我知道主要原因是复选框位于选项卡控件的选项卡面板之外。但是为了我的应用程序的设计目的,我必须把它放在那里。
那么,我如何为选项卡控件的选项卡面板提供自定义形状,以便我可以完美地将内容元素停靠在我想要的位置。
无法选择您的 CheckBox,您可以使用 DataTrigger 使 chexkbox 可见或隐藏,具体取决于是否选择了 Preview TabItem。
我为您的 MainWindow.xaml 做了一些更新,使复选框可以被选中。
<StackPanel Width="635" HorizontalAlignment="Left" Height="458" VerticalAlignment="Top" Margin="0,61,0,0" >
<CheckBox Content="Draggable mode" HorizontalAlignment="Right" VerticalAlignment="Top" Width="110" >
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Visibility" Value="Hidden"></Setter>
<Setter Property="IsEnabled" Value="False"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=myTabControl,Path=SelectedItem.Header}" Value="Preview" >
<Setter Property="Visibility" Value="Visible"></Setter>
<Setter Property="IsEnabled" Value="True"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
<TabControl BorderThickness="0" Background="#222222" Name="myTabControl" SelectionChanged="myTabControl_SelectionChanged">
<TabItem Style="{StaticResource TabItemDefaults}" Header="File manager" FontSize="10" Foreground="#efefef" Margin="5,0,0,0" Width="97" Height="20" FontFamily="Segoe UI" UseLayoutRounding="True" TextOptions.TextFormattingMode="Display" >
<Grid Height="300">
</Grid>
</TabItem>
<TabItem Style="{StaticResource TabItemDefaults}" Header ="Preview" FontSize="10" Foreground="#efefef" Width="67" Height="20" FontFamily="Segoe UI" UseLayoutRounding="True" TextOptions.TextFormattingMode="Display" >
<Grid Height="300">
</Grid>
</TabItem>
</TabControl>
</StackPanel>
我在 WPF 中创建了一个应用程序,我需要使用 TabControl 在内容之间切换。但由于设计目的,我的 Tab 项目的内容在同一水平线上,然后是 Tab 项目 header.
这是我的 Mainwindow.xaml
的代码<Grid Width="635" HorizontalAlignment="Left" Height="458" VerticalAlignment="Top" Margin="0,61,0,0" >
<TabControl Margin="-1" BorderThickness="0" Background="#222222" >
<TabItem Style="{StaticResource TabItemDefaults}" Header="File manager" FontSize="10" Foreground="#efefef" Margin="5,0,0,0" Width="97" Height="20" FontFamily="Segoe UI" UseLayoutRounding="True" TextOptions.TextFormattingMode="Display" >
<Grid>
<Label Name="Folder" Content="Folder:" FontSize="10" Foreground="#efefef" Height="20" Width="40" Margin="-571,-367,0,0" FontFamily="Segoe UI" UseLayoutRounding="True" TextOptions.TextFormattingMode="Display" />
<Button Name ="FolderSelect" Width="532" HorizontalAlignment="Left" VerticalAlignment="Top" Height="33" Margin="85,17,0,0" Background="#1a1a1a"
materialDesign:ShadowAssist.ShadowDepth="Depth0" materialDesign:RippleAssist.Feedback="Transparent" BorderThickness="0" UseLayoutRounding="True"
></Button>
<Label Name="ShowFolders" Content=".." Margin="-479,59,0,0" Background="#1a1a1a" Width="168" Height="373" Foreground="#efefef" ></Label>
<Button
Style="{StaticResource MaterialDesignRaisedButton}"
Width="65" HorizontalAlignment="Left" Height="25" Background="#FF403D3D" Margin="16,292,0,0"
ToolTip="Resource name: MaterialDesignRaisedButton">
<materialDesign:PackIcon Kind="PlusThick" />
</Button>
<Button
Style="{StaticResource MaterialDesignRaisedButton}"
Width="65" HorizontalAlignment="Left" Height="25" Background="#FF403D3D" Margin="82,292,0,0"
ToolTip="Open output folder">
<materialDesign:PackIcon Kind="FolderUpload" />
</Button>
<Label Content="Video recordings:" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="269.2,-22,0,0" Foreground="#efefef" FontSize="10" FontFamily="Segoe UI" UseLayoutRounding="True" TextOptions.TextFormattingMode="Display" />
</Grid>
</TabItem>
<TabItem Style="{StaticResource TabItemDefaults}" Header ="Preview" FontSize="10" Foreground="#efefef" Width="67" Height="20" Margin="-8,0,0,0" FontFamily="Segoe UI" UseLayoutRounding="True" TextOptions.TextFormattingMode="Display" >
<Grid>
<CheckBox Content="Draggable mode" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="520,-22,0,0" Width="110" />
</Grid>
</TabItem>
</TabControl>
</Grid>
选项卡控件和选项卡项都是由我在 App.xaml 中声明的控件模板制作的。
这里是我在App.xaml-
中单独声明的Tab Control的代码<Style TargetType="{x:Type TabControl}" x:Key="TabControlDefaults" x:Name="NewTabcontrol" >
<Setter Property="OverridesDefaultStyle"
Value="True" />
<Setter Property="SnapsToDevicePixels"
Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabControl}">
<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="0,0,4,-1"
IsItemsHost="True"
KeyboardNavigation.TabIndex="1"
Background="Transparent" />
<Border x:Name="Border"
Grid.Row="1"
BorderThickness="1"
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 BorderMediumColor}"/>
</Border.BorderBrush>
<ContentPresenter x:Name="PART_SelectedContentHost"
Margin="4"
ContentSource="SelectedContent" />
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
这里是我在App.xaml-
中单独声明的Tab Items的代码<Style TargetType="{x:Type TabItem}" x:Key="TabItemDefaults" x:Name="NewTabitem" >
<Setter Property="Foreground" Value="#bababa" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid x:Name="Panel" ClipToBounds="true" SnapsToDevicePixels="true" KeyboardNavigation.TabNavigation="Local" >
<ContentPresenter x:Name="ContentSite"
VerticalAlignment="Center"
HorizontalAlignment="Center"
ContentSource="Header"
Margin="10,2"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Black"/>
</Trigger>
<Trigger Property="IsSelected" Value="True">
<!-- <Setter TargetName="Panel" Property="Background" Value="LightSkyBlue" /> -->
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{TemplateBinding Content}">
<TextBlock.TextDecorations>
<TextDecoration PenOffset="4" PenOffsetUnit="Pixel" >
<TextDecoration.Pen>
<Pen Brush="#673ab7" Thickness="4" />
</TextDecoration.Pen>
</TextDecoration>
</TextBlock.TextDecorations>
</TextBlock>
</DataTemplate>
</Setter.Value>
</Setter>
</Trigger>
<Trigger Property="IsSelected" Value="False">
<Setter TargetName="Panel" Property="Background" Value="#212121" />
<Setter Property="Foreground" Value="WhiteSmoke"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
我的问题是复选框(我给了一个红色圆圈)不能正常工作。我知道主要原因是复选框位于选项卡控件的选项卡面板之外。但是为了我的应用程序的设计目的,我必须把它放在那里。
那么,我如何为选项卡控件的选项卡面板提供自定义形状,以便我可以完美地将内容元素停靠在我想要的位置。
无法选择您的 CheckBox,您可以使用 DataTrigger 使 chexkbox 可见或隐藏,具体取决于是否选择了 Preview TabItem。
我为您的 MainWindow.xaml 做了一些更新,使复选框可以被选中。
<StackPanel Width="635" HorizontalAlignment="Left" Height="458" VerticalAlignment="Top" Margin="0,61,0,0" >
<CheckBox Content="Draggable mode" HorizontalAlignment="Right" VerticalAlignment="Top" Width="110" >
<CheckBox.Style>
<Style TargetType="CheckBox">
<Setter Property="Visibility" Value="Hidden"></Setter>
<Setter Property="IsEnabled" Value="False"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=myTabControl,Path=SelectedItem.Header}" Value="Preview" >
<Setter Property="Visibility" Value="Visible"></Setter>
<Setter Property="IsEnabled" Value="True"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</CheckBox.Style>
</CheckBox>
<TabControl BorderThickness="0" Background="#222222" Name="myTabControl" SelectionChanged="myTabControl_SelectionChanged">
<TabItem Style="{StaticResource TabItemDefaults}" Header="File manager" FontSize="10" Foreground="#efefef" Margin="5,0,0,0" Width="97" Height="20" FontFamily="Segoe UI" UseLayoutRounding="True" TextOptions.TextFormattingMode="Display" >
<Grid Height="300">
</Grid>
</TabItem>
<TabItem Style="{StaticResource TabItemDefaults}" Header ="Preview" FontSize="10" Foreground="#efefef" Width="67" Height="20" FontFamily="Segoe UI" UseLayoutRounding="True" TextOptions.TextFormattingMode="Display" >
<Grid Height="300">
</Grid>
</TabItem>
</TabControl>
</StackPanel>