自定义窗口主题的创建与应用

在现代的应用程序开发中,为了提升用户体验,开发者经常需要创建具有独特外观和感觉的窗口主题。本文将介绍如何使用XAML声明式语言来创建一个自定义的窗口主题,并将其应用到应用程序中。

可以从下载Synergy SDK,它包含了完整的源代码。此外,也可以查看在Synergy中的窗口停靠解决方案。将在Twitter账户上发布Synergy SDK的更新信息。

声明式XAML的关键

众所周知,XAML是一种声明式语言,它的简单性意味着没有必要采用传统的编写代码的方式来处理窗口和控件。开发者应该能够简单地创建一个视觉模板,并将其放入控件模板中,以便让控件工作。这正是在开发Synergy时创建无外观窗口功能的动机。

声明一个模板

创建自定义窗口的第一步是创建一个视觉模板。最简单的方法是在Microsoft Blend中创建一个用户控件,然后在XAML中定义扩展点,这些扩展点将在模板应用后激活。一旦视觉元素准备好,接下来要做的就是为CustomWindow创建一个样式,将模板粘贴进去,然后丢弃临时用户控件。

当前实现支持以下扩展点:

  • PART_TITLEBAR (UIElement) - 用于显示窗口标题、拖动和最大化/还原操作
  • PART_MINIMIZE (Button) - 窗口最小化按钮
  • PART_MAXIMIZE_RESTORE (Button) - 最大化还原按钮
  • PART_CLOSE (Button) - 关闭按钮
  • PART_LEFT_BORDER (UIElement) - 左侧可调整大小的边框
  • PART_RIGHT_BORDER (UIElement) - 右侧可调整大小的边框
  • PART_TOP_BORDER (UIElement) - 顶部可调整大小的边框
  • PART_BOTTOM_BORDER (UIElement) - 底部可调整大小的边框

在定义窗口模板时,还必须在AdornerDecorator标签内声明ContentPresenter(最终包含窗口内容),因为这是WPF的要求。

以下是在MixModes.Synergy.Themes项目中的Windows.xaml资源字典内创建的模板:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> <Style x:Key="MainWindow" TargetType="{x:Type Window}"> <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}" /> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type Window}"> <Grid> <Border x:Name="MainBorder" BorderBrush="{DynamicResource MainWindowBorderBrush}" BorderThickness="1" CornerRadius="2" Background="{DynamicResource MainWindowBackgroundBrush}"> <DockPanel LastChildFill="True"> <Rectangle x:Name="PART_LEFT_BORDER" Width="2" Cursor="SizeWE"> <Rectangle.Fill> <SolidColorBrush Color="Transparent" /> </Rectangle.Fill> </Rectangle> <Rectangle x:Name="PART_RIGHT_BORDER" Cursor="SizeWE" Width="2" DockPanel.Dock="Right"> <Rectangle.Fill> <SolidColorBrush Color="Transparent" /> </Rectangle.Fill> </Rectangle> <Rectangle x:Name="PART_TOP_BORDER" Cursor="SizeNS" DockPanel.Dock="Top" Height="2"> <Rectangle.Fill> <SolidColorBrush Color="Transparent" /> </Rectangle.Fill> </Rectangle> <Rectangle x:Name="PART_BOTTOM_BORDER" Cursor="SizeNS" Height="2" DockPanel.Dock="Bottom"> <Rectangle.Fill> <SolidColorBrush Color="Transparent" /> </Rectangle.Fill> </Rectangle> <Border x:Name="PART_TITLEBAR" Margin="2,0,2,2" Height="40" DockPanel.Dock="Top" CornerRadius="2" Background="Transparent"> <DockPanel LastChildFill="False"> <TextBlock Margin="8,0,0,4" VerticalAlignment="Center" FontStretch="UltraExpanded" Foreground="Black" TextTrimming="CharacterEllipsis" TextWrapping="NoWrap" Text="{TemplateBinding Title}" FontSize="16" /> <Button x:Name="PART_CLOSE" DockPanel.Dock="Right" Style="{DynamicResource FlatButton}" VerticalAlignment="Center" Margin="0,0,4,0"> <Image Source="/MixModes.Synergy.Resources;component/Resources/Close.png" Stretch="None" Margin="4" /> </Button> <Button x:Name="PART_MAXIMIZE_RESTORE" DockPanel.Dock="Right" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{DynamicResource FlatButton}"> <Image x:Name="MaximizeRestoreImage" Source="/MixModes.Synergy.Resources;component/Resources/Restore.png" Stretch="None" Margin="4" /> </Button> <Button x:Name="PART_MINIMIZE" HorizontalAlignment="Center" Style="{DynamicResource FlatButton}" VerticalAlignment="Center" DockPanel.Dock="Right"> <Image Margin="4" Source="/MixModes.Synergy.Resources;component/Resources/Minimize.png" Stretch="None" /> </Button> </DockPanel> </Border> <!-- Title bar separator --> <Border Height="1" DockPanel.Dock="Top" Background="{DynamicResource MainWindowTitleBarSeparator}" /> <!-- Actual Window Content --> <AdornerDecorator DockPanel.Dock="Bottom"> <ContentPresenter /> </AdornerDecorator> </DockPanel> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </ResourceDictionary>

这是一个相当简单的主题,它创建了一个带有2像素宽调整器和自定义窗口最小化、最大化和还原按钮的圆角矩形窗口。它还包含一个模板触发器,如果窗口没有最大化,则会更改最大化还原按钮的图像。

继承CustomWindow类

最后一步是从CustomWindow类(它又继承自Window类)继承,而不是直接从Window类继承,并引用前一步创建的样式。这同样非常简单:

  • 导入视觉框架命名空间:xmlns:visualFx="http://mixmodes.com/visualFx"
  • 从CustomWindow类继承:在XAML中使用“visualFx:CustomWindow”作为窗口标签
  • 在visualFx:CustomWindow标签中引用前一步创建的样式:Style="{DynamicResource MainWindow}"

只需要做这些,就可以让自定义窗口工作了!

工作原理

如果打开CustomWindow类,会发现大部分工作发生在AttachToVisualTree方法中,该方法从OnApplyTemplate调用(它又在每次模板应用到自定义窗口时调用)。AttachToVisualTree反过来调用AttachCloseButton、AttachMaximizeButton、AttachMaximizeRestoreButton、AttachTitleBar和AttachBorders方法,每个方法都查询视觉部件(在模板中定义的PART_…命名部件)并通过事件附加功能。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485