自定义窗口边框与系统功能整合

在开发Windows应用程序时,经常需要自定义窗口的外观,以满足特定的设计需求。然而,当将窗口的样式(WindowStyle)设置为"None"以创建一个带有自定义边框的窗口时,会发现失去了标准的Windows功能。本文将介绍如何使用WPFShell Integration Library来解决这些问题,并在此基础上添加标题栏按钮(最小化、最大化/还原、关闭)以及一个窗口图标控件,该控件在单击时显示系统菜单,在双击时关闭窗口。

WPFShell Integration Library提供了一种简单的方式来恢复以下功能,这些功能在将WindowStyle设置为"None"时会丢失:

  • 点击并拖动窗口移动
  • 点击并拖动边框调整大小
  • 双击最大化和还原
  • 右键单击显示系统菜单
  • 拖到顶部最大化,拖开还原
  • 最大化时保留Windows任务栏可见

但是,它对于以下附加功能的帮助不大:

  • 标题栏按钮(最小化、最大化/还原、关闭)
  • 标题栏按钮悬停光晕(本文未涉及)
  • 边框阴影(本文未涉及)
  • 窗口标题在窗口宽度较小时用省略号缩写(本文未涉及)

在尝试创建一个具有完全功能的自定义边框窗口时,找不到类似于标准Windows最小化/最大化/关闭按钮的现有按钮代码,并且希望将这种功能方便地整合到未来的项目中,因此创建了这个新的库,并将其命名为"WPF Custom Chrome Library"。

从标准边框到自定义边框

标准边框是熟悉的Windows 7样式:

<Window x:Class="CustomChromeSample.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:CustomChromeSample" Title="Window 1 - Standard Chrome" Height="350" Width="525">

当将WindowStyle设置为"None"时,会失去标题栏和标题栏按钮,但仍然有调整大小的边框:

<Window x:Class="CustomChromeSample.Window3" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:CustomChromeSample" WindowStyle="None" ResizeMode="NoResize" Title="Window 3 - No Chrome" Height="350" Width="525">

现在有了追求的基本自定义外观,但失去了像标题栏按钮、拖动、双击最大化以及系统菜单这样的标准窗口功能。

恢复标准行为

WPFShell Integration Library恢复了基本功能。以下是Window声明以及来自Shell Integration Library的WindowChrome的XAML:

<Window x:Class="CustomChromeSample.Window4" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:shell="http://schemas.microsoft.com/winfx/2006/xaml/presentation/shell" xmlns:ccl="clr-namespace:CustomChromeLibrary;assembly=CustomChromeLibrary" xmlns:local="clr-namespace:CustomChromeSample" Title="Custom Chrome Sample" Height="350" Width="525"> <shell:WindowChrome.WindowChrome> <shell:WindowChrome ResizeBorderThickness="6" CaptionHeight="43" CornerRadius="25,25,10,10" GlassFrameThickness="0"> </shell:WindowChrome> </shell:WindowChrome.WindowChrome> </Window>

WindowChrome类恢复了设置WindowStyle为"None"时丢失的基本窗口功能。这个类的完整功能以及如何自定义它需要单独一篇文章来介绍。需要注意的一些要点:

  • ResizeBorderThickness设置为6,以便为用户提供足够的区域来点击以调整窗口大小。这不会以任何方式影响窗口的外观。
  • CaptionHeight指定标题栏占用窗口顶部的多少,应该响应点击并拖动、双击最大化以及右键单击系统菜单。
  • CornerRadius指定窗口角落的圆角量。根据文档,只有当标准窗口玻璃框架被禁用时(因为Aero未启用或GlassFrameThickness设置为0),CornerRadius才有效。
  • GlassFrameThickness设置为0,以禁用标准窗口玻璃。

请注意,通常这些WindowChrome设置没有任何视觉效果;它们只控制行为(例外是GlassFrameThickness,如果设置为非零值,将导致显示窗口玻璃)。需要将WindowChrome设置与自定义边框窗口的视觉尺寸相匹配。

另外,当WindowChrome类应用于窗口时,它会自动设置WindowStyle="None"和ResizeMode="NoResize",所以不需要这样做。

完成自定义边框窗口的最后步骤是:

  • 使用预定义的CaptionButtons用户控件或单独的CaptionButton控件添加标题栏按钮。
  • 使用WindowIcon控件在单击图标时显示系统菜单,在双击图标时关闭窗口。
  • 从自己的自定义窗口基类派生窗口,该类提供了一个属性,正确计算最大化时标题栏按钮的边距。

首先展示窗口及其XAML,然后解释底层代码和支持库。

<ccl:CustomChromeWindow x:Class="CustomChromeSample.Window5" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:shell="http://schemas.microsoft.com/winfx/2006/xaml/presentation/shell" xmlns:ccl="clr-namespace:CustomChromeLibrary;assembly=CustomChromeLibrary" xmlns:local="clr-namespace:CustomChromeSample" Title="Custom Chrome Sample" Height="350" Width="525"> <shell:WindowChrome.WindowChrome> <shell:WindowChrome ResizeBorderThickness="6" CaptionHeight="43" CornerRadius="25,25,10,10" GlassFrameThickness="0"> </shell:WindowChrome> </shell:WindowChrome.WindowChrome> <Window.Resources> <ResourceDictionary> <local:CaptionButtonRectToMarginConverter x:Key="CaptionButtonMarginConverter" /> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="Resources/GlassButton.xaml" /> <ResourceDictionary Source="Resources/GlassIcon.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Window.Resources> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <!-- 提供整个表单的背景。在实践中,这看起来像是窗口的调整大小边框,因为标题和窗口内容遮挡了其余部分 --> <Border CornerRadius="10,10,5,5" Grid.RowSpan="2" BorderThickness="3" BorderBrush="LightSteelBlue"> <Border.Background> <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1"> <GradientStop Color="#99bbbbff" Offset="0" /> <GradientStop Color="#ff7777bb" Offset="1" /> </LinearGradientBrush> </Border.Background> </Border> <!-- 标题栏 --> <Border CornerRadius="10,10,0,0" BorderThickness="3,3,3,1" BorderBrush="LightSteelBlue" Margin="{Binding Path=CaptionButtonMargin}"> <Border.Background> <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1"> <GradientStop Color="#ffbbbbff" Offset="0" /> <GradientStop Color="#ff7777bb" Offset="1" /> </LinearGradientBrush> </Border.Background> <StackPanel Orientation="Horizontal" Margin="0" VerticalAlignment="Top"> <ccl:WindowIcon Width="35" Height="35" Background="#ff0000bb" Margin="7,3,5,5" Style="{StaticResource GlassIcon}" /> <TextBlock Text="Window 5 - Caption Buttons" FontFamily="Calibri" FontWeight="Bold" FontSize="26" Foreground="#FF000044" VerticalAlignment="Center" /> </StackPanel> </Border> <!-- 最小化/最大化/关闭按钮 --> <ccl:CaptionButtons/> <!-- 内容 --> <Grid Grid.Row="1"> <TextBlock Grid.Row="1" Margin="10" FontFamily="Verdana" FontSize="14"> Complete custom chrome with caption buttons. </TextBlock> </Grid> </Grid> </ccl:CustomChromeWindow>
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485