原文地址:在 WPF 中使用 WindowChrome 自定义标题栏
本文将介绍在 WPF 中如何使用 WindowChrome 自定义标题栏。
在 <Window></Window>
节点里写如下代码便能够完成客户区(Client Area)到非客户区(Non-client Area)的覆盖:
<WindowChrome.WindowChrome>
<WindowChrome />
</WindowChrome.WindowChrome>
样式已经被遮挡
现在,为了能够观察到 WindowChrome
各种属性设置的效果,我们为 Window
定义一个新的 Template
,里面就是空的,这样就没有什么内容能够遮挡我们设置的样式了。
<Window.Template>
<ControlTemplate TargetType="Window">
<Border />
</ControlTemplate>
</Window.Template>
没有遮挡的窗口
然而即便如此,我们也只解决了系统主题色边框的问题,没有解决调整窗口的拖拽热区问题。而且边框还如此之丑。
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="0 30 0 0" NonClientFrameEdges="Left,Bottom,Right"/>
</WindowChrome.WindowChrome>
设置 GlassFrameThickness 和 NonClientFrameEdges
到这里,我们算是模拟得比较像了。
WindowChrome
提供客户区内容覆盖到非客户区的能力,所以我们通过定制 Window
的 ControlTemplate
能够在保证原生窗口体验的同时,尽可能定制我们的窗口样式。
<Window.Template>
<ControlTemplate TargetType="Window">
<Border Name="RootBorder">
<Grid Background="Aqua">
<AdornerDecorator>
<ContentPresenter/>
</AdornerDecorator>
</Grid>
</Border>
</ControlTemplate>
</Window.Template>
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="0 30 0 0" NonClientFrameEdges="Left,Bottom,Right"/>
</WindowChrome.WindowChrome>
<Grid>
<TextBlock Text="12345"></TextBlock>
</Grid>
客户区内容覆盖到非客户区
可以看到 <Grid>
(客户区)的内容覆盖到了非客户区,并且默认的“最小化”、“最大化”、“关闭”功能还是在的,也是可以点击的,只是看不见了而已(被客户区覆盖)。
我们调整一下边距,让非客户区域露出来。
<Border Name="RootBorder" Padding="0 30 0 0" BorderBrush="Transparent" BorderThickness="4 0 4 4">
<Grid Background="Aqua">
<AdornerDecorator>
<ContentPresenter/>
</AdornerDecorator>
</Grid>
</Border>
调整客户区域的边距
把 Grid
分为上下两行,上面一行作为标题栏,下面一行作为内容主体。
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<!--标题栏 开始-->
<Border Grid.Row="0" Height="30" Margin="0 -29 0 0">
<DockPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Right">
<Button Content="最小化"></Button>
<Button Content="最大化"></Button>
<Button Content="向下还原"></Button>
<Button Content="关闭"></Button>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock
Text="自定义的标题栏"
VerticalAlignment="Center"></TextBlock>
</StackPanel>
</DockPanel>
</Border>
<!--标题栏 结束-->
<Grid Grid.Row="1">
<TextBlock Text="主体内容区域"></TextBlock>
</Grid>
</Grid>
定制布局
现在,点击右上角,还是会触发默认的“最小化”、“最大化”、“关闭”行为。所以,我们需要禁用它的默认行为。
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="0 30 0 0" NonClientFrameEdges="Left,Bottom,Right" UseAeroCaptionButtons="False"/>
</WindowChrome.WindowChrome>
定义命令
<Window.CommandBindings>
<CommandBinding Command="{x:Static SystemCommands.CloseWindowCommand}" CanExecute="CommandBinding_OnCanExecute" Executed="CommandBinding_OnExecuted_CloseWindow"/>
<CommandBinding Command="{x:Static SystemCommands.MaximizeWindowCommand}" CanExecute="CommandBinding_OnCanExecute" Executed="CommandBinding_OnExecuted_MaximizeWindow"/>
<CommandBinding Command="{x:Static SystemCommands.MinimizeWindowCommand}" CanExecute="CommandBinding_OnCanExecute" Executed="CommandBinding_OnExecuted_MinimizeWindow"/>
<CommandBinding Command="{x:Static SystemCommands.RestoreWindowCommand}" CanExecute="CommandBinding_OnCanExecute" Executed="CommandBinding_OnExecuted_RestoreWindow"/>
</Window.CommandBindings>
按钮上绑定命令
<Button Name="ButtonMinimizeWindow" Content="最小化"
WindowChrome.IsHitTestVisibleInChrome="True"
Command="{x:Static SystemCommands.MinimizeWindowCommand}"></Button>
<Button Name="ButtonMaximizeWindow" Content="最大化"
WindowChrome.IsHitTestVisibleInChrome="True"
Command="{x:Static SystemCommands.MaximizeWindowCommand}"></Button>
<Button Name="ButtonRestoreWindow" Content="向下还原"
WindowChrome.IsHitTestVisibleInChrome="True"
Command="{x:Static SystemCommands.RestoreWindowCommand}"></Button>
<Button Name="ButtonCloseWindow" Content="关闭"
WindowChrome.IsHitTestVisibleInChrome="True"
Command="{x:Static SystemCommands.CloseWindowCommand}"></Button>
定义字体资源,参考 https://blog.csdn.net/mybelief321/article/details/102461597
<Window.Resources>
<ResourceDictionary>
<FontFamily x:Key="IconFont">pack://application:,,,/WindowChromeExample;component/#iconfont,</FontFamily>
</ResourceDictionary>
</Window.Resources>
使用字体资源
<Button Name="ButtonMinimizeWindow" FontFamily="{StaticResource IconFont}" Content="" Width="24" Height="24"
WindowChrome.IsHitTestVisibleInChrome="True"
Command="{x:Static SystemCommands.MinimizeWindowCommand}"></Button>
<Button Name="ButtonMaximizeWindow" FontFamily="{StaticResource IconFont}" Content="" Width="24" Height="24"
WindowChrome.IsHitTestVisibleInChrome="True"
Command="{x:Static SystemCommands.MaximizeWindowCommand}"></Button>
<Button Name="ButtonRestoreWindow" FontFamily="{StaticResource IconFont}" Content="" Width="24" Height="24"
Visibility="Collapsed"
WindowChrome.IsHitTestVisibleInChrome="True"
Command="{x:Static SystemCommands.RestoreWindowCommand}"></Button>
<Button Name="ButtonCloseWindow" FontFamily="{StaticResource IconFont}" Content="" Width="24" Height="24"
WindowChrome.IsHitTestVisibleInChrome="True"
Command="{x:Static SystemCommands.CloseWindowCommand}"></Button>
美化按钮
默认的按钮还是会显示,个他加给背景,就看不到了。
<Border Grid.Row="0" Height="30" Margin="0 -29 0 0">
<DockPanel Background="Red">
<StackPanel Orientation="Horizontal" DockPanel.Dock="Right">
<Button Name="ButtonMinimizeWindow" FontFamily="{StaticResource IconFont}" Content="" Width="24" Height="24"
WindowChrome.IsHitTestVisibleInChrome="True"
Command="{x:Static SystemCommands.MinimizeWindowCommand}"></Button>
<Button Name="ButtonMaximizeWindow" FontFamily="{StaticResource IconFont}" Content="" Width="24" Height="24"
WindowChrome.IsHitTestVisibleInChrome="True"
Command="{x:Static SystemCommands.MaximizeWindowCommand}"></Button>
<Button Name="ButtonRestoreWindow" FontFamily="{StaticResource IconFont}" Content="" Width="24" Height="24"
Visibility="Collapsed"
WindowChrome.IsHitTestVisibleInChrome="True"
Command="{x:Static SystemCommands.RestoreWindowCommand}"></Button>
<Button Name="ButtonCloseWindow" FontFamily="{StaticResource IconFont}" Content="" Width="24" Height="24"
WindowChrome.IsHitTestVisibleInChrome="True"
Command="{x:Static SystemCommands.CloseWindowCommand}"></Button>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock
Text="自定义的标题栏"
VerticalAlignment="Center"></TextBlock>
</StackPanel>
</DockPanel>
</Border>
红色背景
<Window x:Class="WindowChromeExample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="450" Width="800">
<!--字体资源-->
<Window.Resources>
<ResourceDictionary>
<FontFamily x:Key="IconFont">pack://application:,,,/WindowChromeExample;component/#iconfont,</FontFamily>
</ResourceDictionary>
</Window.Resources>
<!--自定义标题栏 开始-->
<Window.Template>
<ControlTemplate TargetType="Window">
<Border Name="RootBorder" Padding="0 30 0 0" BorderBrush="Transparent" BorderThickness="4 0 4 4">
<Grid Background="{TemplateBinding Background}">
<AdornerDecorator>
<ContentPresenter/>
</AdornerDecorator>
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="WindowState" Value="Maximized">
<Setter TargetName="RootBorder" Property="BorderThickness" Value="8" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Template>
<!--自定义标题栏 结束-->
<WindowChrome.WindowChrome>
<WindowChrome GlassFrameThickness="0 30 0 0" NonClientFrameEdges="Left,Bottom,Right" UseAeroCaptionButtons="False"/>
</WindowChrome.WindowChrome>
<!--标题栏按钮事件 开始-->
<Window.CommandBindings>
<CommandBinding Command="{x:Static SystemCommands.CloseWindowCommand}" CanExecute="CommandBinding_OnCanExecute" Executed="CommandBinding_OnExecuted_CloseWindow"/>
<CommandBinding Command="{x:Static SystemCommands.MaximizeWindowCommand}" CanExecute="CommandBinding_OnCanExecute" Executed="CommandBinding_OnExecuted_MaximizeWindow"/>
<CommandBinding Command="{x:Static SystemCommands.MinimizeWindowCommand}" CanExecute="CommandBinding_OnCanExecute" Executed="CommandBinding_OnExecuted_MinimizeWindow"/>
<CommandBinding Command="{x:Static SystemCommands.RestoreWindowCommand}" CanExecute="CommandBinding_OnCanExecute" Executed="CommandBinding_OnExecuted_RestoreWindow"/>
</Window.CommandBindings>
<!--标题栏按钮事件 结束-->
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<!--标题栏 开始-->
<Border Grid.Row="0" Height="30" Margin="0 -29 0 0">
<DockPanel Background="White">
<StackPanel Orientation="Horizontal" DockPanel.Dock="Right">
<Button
Name="ButtonMinimizeWindow"
WindowChrome.IsHitTestVisibleInChrome="True"
FontFamily="{StaticResource IconFont}"
Width="32"
Content=""
ToolTip="最小化"
Command="{x:Static SystemCommands.MinimizeWindowCommand}"></Button>
<Button
Name="ButtonMaximizeWindow"
WindowChrome.IsHitTestVisibleInChrome="True"
FontFamily="{StaticResource IconFont}"
Width="32"
Content=""
ToolTip="最大化"
Command="{x:Static SystemCommands.MaximizeWindowCommand}"></Button>
<Button
Name="ButtonRestoreWindow"
WindowChrome.IsHitTestVisibleInChrome="True"
FontFamily="{StaticResource IconFont}"
Width="32"
Content=""
ToolTip="向下还原"
Visibility="Collapsed"
Command="{x:Static SystemCommands.RestoreWindowCommand}"></Button>
<Button
Name="ButtonCloseWindow"
WindowChrome.IsHitTestVisibleInChrome="True"
FontFamily="{StaticResource IconFont}"
Width="32"
Content=""
ToolTip="关闭"
Command="{x:Static SystemCommands.CloseWindowCommand}"></Button>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock
Text="自定义标题栏"
VerticalAlignment="Center"></TextBlock>
</StackPanel>
</DockPanel>
</Border>
<!--标题栏 结束-->
<Grid Grid.Row="1">
<TextBlock Text="主体内容"></TextBlock>
</Grid>
</Grid>
</Window>
using System;
using System.Windows;
using System.Windows.Input;
namespace WindowChromeExample
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
StateChanged += MainWindow_StateChanged;
}
private void MainWindow_StateChanged(object? sender, EventArgs e)
{
if (WindowState == WindowState.Maximized)
{
ButtonRestoreWindow.Visibility = Visibility.Visible;
ButtonMaximizeWindow.Visibility = Visibility.Collapsed;
}
else
{
ButtonRestoreWindow.Visibility = Visibility.Collapsed;
ButtonMaximizeWindow.Visibility = Visibility.Visible;
}
}
private void CommandBinding_OnCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
private void CommandBinding_OnExecuted_MinimizeWindow(object sender, ExecutedRoutedEventArgs e)
{
SystemCommands.MinimizeWindow(this);
}
private void CommandBinding_OnExecuted_MaximizeWindow(object sender, ExecutedRoutedEventArgs e)
{
SystemCommands.MaximizeWindow(this);
}
private void CommandBinding_OnExecuted_RestoreWindow(object sender, ExecutedRoutedEventArgs e)
{
SystemCommands.RestoreWindow(this);
}
private void CommandBinding_OnExecuted_CloseWindow(object sender, ExecutedRoutedEventArgs e)
{
SystemCommands.CloseWindow(this);
}
}
}
最终效果
到这里,已经完整的介绍了在 WPF 中如何使用 WindowChrome 自定义标题栏。