Skip to content

astrid9527/WpfWindowChromeExample

Repository files navigation

WpfWindowChromeExample

原文地址:在 WPF 中使用 WindowChrome 自定义标题栏

本文将介绍在 WPF 中如何使用 WindowChrome 自定义标题栏。

一、使用 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>

没有遮挡的窗口

没有遮挡的窗口

然而即便如此,我们也只解决了系统主题色边框的问题,没有解决调整窗口的拖拽热区问题。而且边框还如此之丑。

1.1 GlassFrameThicknessNonClientFrameEdges

<WindowChrome.WindowChrome>
    <WindowChrome GlassFrameThickness="0 30 0 0" NonClientFrameEdges="Left,Bottom,Right"/>
</WindowChrome.WindowChrome>

设置 GlassFrameThickness 和 NonClientFrameEdges

设置 GlassFrameThickness 和 NonClientFrameEdges

到这里,我们算是模拟得比较像了。

二、定制 Window 的控件模板

WindowChrome 提供客户区内容覆盖到非客户区的能力,所以我们通过定制 WindowControlTemplate 能够在保证原生窗口体验的同时,尽可能定制我们的窗口样式。

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

调整客户区域的边距

调整客户区域的边距

2.1 定制布局

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>

2.2 自定义“最小化”、“最大化”、“关闭”事件

定义命令

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

2.3 美化按钮

定义字体资源,参考 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="&#xe629;"  Width="24" Height="24"
        WindowChrome.IsHitTestVisibleInChrome="True"
        Command="{x:Static SystemCommands.MinimizeWindowCommand}"></Button>
<Button Name="ButtonMaximizeWindow" FontFamily="{StaticResource IconFont}" Content="&#xe653;"  Width="24" Height="24"
        WindowChrome.IsHitTestVisibleInChrome="True"
        Command="{x:Static SystemCommands.MaximizeWindowCommand}"></Button>
<Button Name="ButtonRestoreWindow" FontFamily="{StaticResource IconFont}" Content="&#xe677;"  Width="24" Height="24"
        Visibility="Collapsed"
        WindowChrome.IsHitTestVisibleInChrome="True"
        Command="{x:Static SystemCommands.RestoreWindowCommand}"></Button>
<Button Name="ButtonCloseWindow" FontFamily="{StaticResource IconFont}" Content="&#xeaf2;"  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="&#xe629;"  Width="24" Height="24"
                    WindowChrome.IsHitTestVisibleInChrome="True"
                    Command="{x:Static SystemCommands.MinimizeWindowCommand}"></Button>
            <Button Name="ButtonMaximizeWindow" FontFamily="{StaticResource IconFont}" Content="&#xe653;"  Width="24" Height="24"
                    WindowChrome.IsHitTestVisibleInChrome="True"
                    Command="{x:Static SystemCommands.MaximizeWindowCommand}"></Button>
            <Button Name="ButtonRestoreWindow" FontFamily="{StaticResource IconFont}" Content="&#xe677;"  Width="24" Height="24"
                    Visibility="Collapsed"
                    WindowChrome.IsHitTestVisibleInChrome="True"
                    Command="{x:Static SystemCommands.RestoreWindowCommand}"></Button>
            <Button Name="ButtonCloseWindow" FontFamily="{StaticResource IconFont}" Content="&#xeaf2;"  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>

红色背景

红色背景

三、完整代码

3.1 XAML 代码

<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="&#xe629;"
                        ToolTip="最小化"
                        Command="{x:Static SystemCommands.MinimizeWindowCommand}"></Button>
                    <Button
                        Name="ButtonMaximizeWindow"
                        WindowChrome.IsHitTestVisibleInChrome="True"
                        FontFamily="{StaticResource IconFont}"
                        Width="32"
                        Content="&#xe653;"
                        ToolTip="最大化"
                        Command="{x:Static SystemCommands.MaximizeWindowCommand}"></Button>
                    <Button
                        Name="ButtonRestoreWindow"
                        WindowChrome.IsHitTestVisibleInChrome="True"
                        FontFamily="{StaticResource IconFont}"
                        Width="32"
                        Content="&#xe677;"
                        ToolTip="向下还原"
                        Visibility="Collapsed"
                        Command="{x:Static SystemCommands.RestoreWindowCommand}"></Button>
                    <Button
                        Name="ButtonCloseWindow"
                        WindowChrome.IsHitTestVisibleInChrome="True"
                        FontFamily="{StaticResource IconFont}"
                        Width="32"
                        Content="&#xeaf2;"
                        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>

3.2 C#

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);
        }
    }
}

3.3 最终效果

最终效果

最终效果

源码地址

到这里,已经完整的介绍了在 WPF 中如何使用 WindowChrome 自定义标题栏。

源码地址:https://github.com/astrid9527/WpfWindowChromeExample

参考

About

在 WPF 中使用 WindowChrome 自定义标题栏

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages