65.9K
CodeProject 正在变化。 阅读更多。
Home

WPF 自定义 Chrome 库

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.78/5 (33投票s)

2010年12月3日

Ms-PL

4分钟阅读

viewsIcon

166077

downloadIcon

12998

在 WPF 中创建具有自定义 Chrome 和标题栏按钮的完整功能窗口

引言

如果您曾尝试使用 WindowStyle=”None” 来创建带有自定义边框的窗口,您肯定已经注意到您会丢失标准的 Windows 功能。 本文展示了如何使用 WPF Shell Integration Library 来解决这些问题,并在其基础上添加了标题按钮(最小化、最大化/还原和关闭)以及一个在单击时显示系统菜单并在双击时关闭的窗口图标控件。

背景

WPF Shell Integration Library 提供了一种简单的方法来解决当 WindowStyle 设置为 "None" 时丢失的以下功能:

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

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

  • 标题按钮(最小化、最大化/还原、关闭)
  • 标题按钮鼠标悬停发光效果(本文未涉及)
  • 边框阴影(本文未涉及)
  • 窗口标题在窗口宽度较小时截断并显示省略号(本文未涉及)

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

从标准边框到自定义边框

标准边框

这是我们都熟悉的标准 Windows 边框(在 Windows 7 中)

Window1.png

这是具有标准边框的窗口的基本 XAML 代码片段

<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" 时,您将失去标题栏和标题按钮,但仍然拥有调整大小的边框

Window2.png

ResizeMode 设置为 "NoResize" 以移除调整大小的边框

Window3.png

现在我们有了想要的基本自定义外观,但是我们丢失了标题按钮、拖动、双击最大化和系统菜单等标准窗口功能。这是窗口声明的 XAML 代码:

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

恢复标准行为

WPF Shell Integration Library 可恢复基本功能。

Window4.png

这是窗口声明的 XAML 代码以及来自 Shell Integration Library 的 WindowChrome

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

WindowChrome 类恢复了我们在将 WindowStyle 设置为 "None" 时丢失的基本窗口功能。该类的全部功能及其自定义方法需要另写一篇文章。需要注意的一些重要事项:

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

请注意,总的来说,这些 WindowChrome 设置没有视觉效果;它们仅控制行为(例外是 GlassFrameThickness,如果设置为非零值,则会显示窗口玻璃)。我们应该根据我们自定义边框窗口的视觉尺寸来匹配 WindowChrome 设置。

另请注意,当 WindowChrome 类应用于我们的窗口时,它会自动设置 WindowStyle="None" ResizeMode 为 "NoResize",因此我们不必手动设置。

有关 WindowChrome 类的更多信息,请参阅 MSDN 文档

功能齐全的自定义边框窗口

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

  • 使用预定义的 CaptionButtons 用户控件添加标题按钮,或者如果您想自定义按钮,则使用单独的 CaptionButton 控件。
  • 使用 WindowIcon 控件在单击图标时显示系统菜单,并在双击图标时关闭窗口。
  • 使窗口继承自我们自己的自定义窗口基类,该基类提供一个属性,可以正确计算窗口最大化时的标题按钮边距。

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

Window5.png

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

		<!--provide the background for the entire form.
		In practice, this appears as the window's resize border,
		because the title and window content obscure the rest-->
		<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>

		<!--title bar-->
		<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>

			<!--Window Icon and Title-->
			<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>

		<!--min/max/close buttons-->
		<ccl:CaptionButtons/>

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

CustomChromeLibrary

提供自定义边框窗口的完整功能的核心是 CustomChromeLibrary。该库提供了以下功能:

  • CaptionButton - 扩展 Button,提供依赖项属性 CornerRadiusHoverBackgroundPressedBackground。作为最小化、最大化、关闭和其他标题按钮的基类。
    • MinimizeButton
    • MaximizeButton
    • CloseButton (关闭按钮)
  • CaptionButtons - 将 MinimizeButtonMaximizeButtonCloseButton 组合成一个标准的组,可以方便地包含在自定义边框窗口中。
  • WindowIcon - 提供窗口图标的包装器,可在单击时显示系统菜单,并在双击时关闭窗口。
  • CustomChromeWindow - 扩展 Window,添加 CaptionButtonMargin,为窗口最大化时的标题按钮和窗口图标提供调整后的边距。

本文的第二部分将更详细地解释这些类以及如何使用它们。

© . All rights reserved.