WPF 使用 WindowChrome,在自定义窗口标题栏的同时最大程度保留原生窗口样式(类似 UWP/Chrome)

本文介绍了如何使用 WPF 的 WindowChrome 类来定制窗口样式,旨在在保持原生 Windows 窗口体验的同时,允许一定程度的自定义。通过设置 GlassFrameThickness 和 NonClientFrameEdges 属性,可以调整窗口边框和拖拽热区,以达到接近原生窗口的效果。此外,文章还讨论了定制标题栏和窗口控件模板的方法。
摘要由CSDN通过智能技术生成

WPF 自定义窗口样式有多种方式,不过基本核心实现都是在修改 Win32 窗口样式。然而,Windows 上的应用就应该有 Windows 应用的样子嘛,在保证自定义的同时也能与其他窗口样式保持一致当然能最大程度保证 Windows 操作系统上的体验一致性。

本文将使用 WindowChrome 来自定义窗口样式,使其既保留原生窗口样式和交互习惯,又能够具备一定的自定义空间。


使用 Windows 原生窗口体验的应用

在自定义窗口样式的同时保证一致的 Windows 窗口风格体验的优秀应用有这些:

  • Windows 10 UWP 应用
    • 当然少不了 UWP 应用,毕竟这就是 Windows 10 窗口体验的代表
  • Google Chrome
    • 如果我不提第三方应用,你们肯定会说微软都是自己拿内部 API,拿黑科技做的
  • Windows 文件资源管理器
    • Windows 文件资源管理器也有一些自定义(例如在标题栏上放按钮,虽然实际做得很丑),不过整体来说还没 Chrome 做得精致呢

Chrome 普通窗口
▲ Chrome 普通窗口

Chrome 最大化窗口
▲ Chrome 最大化窗口

为什么不做无边框窗口?

WPF 自定义窗口可是非常容易的,完全自定义样式、异形都不在话下。

<Window x:Class="Walterlv.Whitman.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Walterlv.Whitman"
        mc:Ignorable="d" Title="Whitman" Width="800" Height="450"
        WindowStyle="None" AllowsTransparency="True">
</Window>

然而,这就不贴近原生窗口体验了,有这么多事情都不好模拟:

  • 最小化、最大化、关闭按钮
    • 按钮要多大?位置在哪里?图标边距又是多少,颜色值又是什么?鼠标滑入划出的动画效果如何?
  • 窗口标题栏交互
    • 标题栏上有右键菜单,如果自己模拟,基本上这个就要自己重新实现了。
  • 窗口的位置和尺寸
    • 你需要自己实现一套窗口的拖拽调整位置功能,需要自己实现一套拖拽调整大小的功能。而自己实现的方式在触摸屏下还很容易出现失效的情况。
  • 窗口的阴影
    • 要完全模拟 Windows 10 上的窗口阴影效果实在是一件头疼的事情,因为并不知道各种阴影参数是多少;就算模拟出来,性能也是个严重的问题。
  • 窗口的边框颜色
    • 虽然窗口边框是被广为吐槽的一点,但为了保证一致的窗口体验,这也是需要模拟的;正常情况和失焦的情况颜色还不一样。
  • 第三方应用集成
    • 第三方截图应用可以毫无
  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
自定义窗口样式时,我们可以通过以下步骤来处理最大化时边框溢出屏幕外侧的问题: 1. 给窗口添加一个最大化的标志,用于判断窗口是否处于最大化状态。 2. 在窗口最大化时,需要计算窗口的边框大小,将窗口的边框大小减去屏幕的工作区域大小,得到窗口最大化时应该占据的大小。 3. 如果窗口最大化时超出了屏幕的工作区域,需要将窗口的位置调整到屏幕的可见范围内。 4. 在窗口最大化状态恢复到原来的大小时,需要将窗口的位置和大小调整回原来的状态。 下面是示例代码: ```csharp private bool isMaximized = false; // 窗口是否处于最大化状态 private void MaximizeWindow() { if (!isMaximized) { // 计算窗口最大化时应该占据的大小 var screen = Screen.FromHandle(new WindowInteropHelper(this).Handle); var workArea = screen.WorkingArea; var borderThickness = this.BorderThickness; var width = workArea.Width - borderThickness.Left - borderThickness.Right; var height = workArea.Height - borderThickness.Top - borderThickness.Bottom; var left = workArea.Left + borderThickness.Left; var top = workArea.Top + borderThickness.Top; // 将窗口的位置和大小调整到屏幕的可见范围内 this.Left = left; this.Top = top; this.Width = width; this.Height = height; isMaximized = true; } } private void RestoreWindow() { if (isMaximized) { // 将窗口的位置和大小调整回原来的状态 this.WindowState = WindowState.Normal; isMaximized = false; } } private void Window_SizeChanged(object sender, SizeChangedEventArgs e) { if (isMaximized) { // 如果窗口最大化时超出了屏幕的工作区域,需要将窗口的位置调整到屏幕的可见范围内 var screen = Screen.FromHandle(new WindowInteropHelper(this).Handle); var workArea = screen.WorkingArea; var left = workArea.Left + this.BorderThickness.Left; var top = workArea.Top + this.BorderThickness.Top; if (this.Left != left || this.Top != top) { this.Left = left; this.Top = top; } } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值