【WPF】WindowChrome 自定义窗口完美实现
WindowChrome 自定义窗口完美实现
- 简介
- 效果图
- 自定义最小化、最大化、关闭按钮
- 布局实现
- 结语
简介
Microsoft官网关于 WindowChome 的介绍
截取Microsoft文章的一段话:
若要在保留其标准功能时自定义窗口,可以使用该WindowChrome类。 该WindowChrome类将窗口框架的功能与视觉对象分开,并允许你控制应用程序窗口的客户端和非客户端区域之间的边界。 通过WindowChrome该类,可以通过扩展工作区来覆盖非工作区,将 WPF 内容置于窗口框架中。 同时,它通过两个不可见区域保留系统行为: 调整边框 和 标题 区域的大小。
效果图


自定义最小化、最大化、关闭按钮
- 最小化按钮
<Stylex:Key="SystemCloseButtonStyle"BasedOn="{StaticResource SystemButtonStyleBase}"TargetType="{x:Type Button}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type Button}"><Grid Background="{TemplateBinding Background}"><Viewbox Width="12" Height="12"><Path Data="M550.848 502.496l308.64-308.896a31.968 31.968 0 1 0-45.248-45.248l-308.608 308.896-308.64-308.928a31.968 31.968 0 1 0-45.248 45.248l308.64 308.896-308.64 308.896a31.968 31.968 0 1 0 45.248 45.248l308.64-308.896 308.608 308.896a31.968 31.968 0 1 0 45.248-45.248l-308.64-308.864z" Fill="{TemplateBinding BorderBrush}" /></Viewbox><ContentPresenterHorizontalAlignment="Center"VerticalAlignment="Center"Content="{TemplateBinding Content}" /></Grid><ControlTemplate.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter Property="Background" Value="{StaticResource CloseColor}" /><Setter Property="BorderBrush" Value="{StaticResource DominantColor}" /></Trigger><Trigger Property="IsFocused" Value="True"><Setter Property="FocusVisualStyle" Value="{x:Null}" /></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter>
</Style>
- 最大化按钮
<Stylex:Key="SystemMaxButtonStyle"BasedOn="{StaticResource SystemButtonStyleBase}"TargetType="{x:Type Button}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type Button}"><Grid Background="{TemplateBinding Background}"><Viewbox Width="12" Height="12"><Path Data="M959.72 0H294.216a63.96 63.96 0 0 0-63.96 63.96v127.92H64.28A63.96 63.96 0 0 0 0.32 255.84V959.4a63.96 63.96 0 0 0 63.96 63.96h703.56a63.96 63.96 0 0 0 63.96-63.96V792.465h127.92a63.96 63.96 0 0 0 63.96-63.96V63.96A63.96 63.96 0 0 0 959.72 0zM767.84 728.505V959.4H64.28V255.84h703.56z m189.322 0H831.8V255.84a63.96 63.96 0 0 0-63.96-63.96H294.216V63.96H959.72z" Fill="{TemplateBinding BorderBrush}" /></Viewbox><ContentPresenterHorizontalAlignment="Center"VerticalAlignment="Center"Content="{TemplateBinding Content}" /></Grid><ControlTemplate.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter Property="Background" Value="{StaticResource SuspensionColor}" /></Trigger><Trigger Property="IsFocused" Value="True"><Setter Property="FocusVisualStyle" Value="{x:Null}" /></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter>
</Style>
- 关闭按钮
<Stylex:Key="SystemMinButtonStyle"BasedOn="{StaticResource SystemButtonStyleBase}"TargetType="{x:Type Button}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type Button}"><Grid Background="{TemplateBinding Background}"><Viewbox Width="12" Height="10"><Path Data="M928.2 548h-832c-17.7 0-32-14.3-32-32s14.3-32 32-32h832c17.7 0 32 14.3 32 32s-14.3 32-32 32z" Fill="{TemplateBinding BorderBrush}" /></Viewbox><ContentPresenterHorizontalAlignment="Center"VerticalAlignment="Center"Content="{TemplateBinding Content}" /></Grid><ControlTemplate.Triggers><Trigger Property="IsMouseOver" Value="True"><Setter Property="Background" Value="{StaticResource SuspensionColor}" /></Trigger><Trigger Property="IsFocused" Value="True"><Setter Property="FocusVisualStyle" Value="{x:Null}" /></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter>
</Style>
/// <summary>
/// 窗口移动
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Move_Click(object sender, System.Windows.Input.MouseButtonEventArgs e) => this.DragMove();/// <summary>
/// 最小化
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnMin_Click(object sender, RoutedEventArgs e) => WindowState = WindowState.Minimized;/// <summary>
/// 最大化/还原
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnMax_Click(object sender, RoutedEventArgs e) => WindowState = WindowState is WindowState.Normal ? WindowState.Maximized : WindowState.Normal;/// <summary>
/// 关闭
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void BtnClose_Click(object sender, RoutedEventArgs e) => Application.Current.Shutdown();
布局实现
首先我们需要在
MainWindow也就是我们的主窗口中的Window.Resources中实现WindowChrome的基本样式:
WindowChrome.ResizeBorderThickness设置不可见边框宽度
WindowChrome.CaptionHeight>设置属于标题栏的范围——高度
WindowChrome.UseAeroCaptionButtons是否启用默认系统按钮功能——三大金刚键
WindowChrome.NonClientFrameEdges设置客户区域,使用bottom可以实现加载时空白窗口而不显示默认窗口,提升用户体验
<Windowx:Class="SignalRClient.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:local="clr-namespace:SignalRClient"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"Title=""Width="880"Height="620"MinWidth="700"MinHeight="500"Style="{StaticResource mainWindow}"WindowChrome.WindowChrome="{DynamicResource WindowChromeKey}"WindowStartupLocation="CenterScreen"mc:Ignorable="d"><Window.Resources><WindowChrome x:Key="WindowChromeKey"><WindowChrome.ResizeBorderThickness><Thickness>5</Thickness></WindowChrome.ResizeBorderThickness><WindowChrome.CaptionHeight>60</WindowChrome.CaptionHeight><WindowChrome.UseAeroCaptionButtons>false</WindowChrome.UseAeroCaptionButtons><WindowChrome.NonClientFrameEdges>bottom</WindowChrome.NonClientFrameEdges></WindowChrome></Window.Resources>
</Window>
重写窗口,实现最大化窗口下,标题栏及客户区域偏移问题的修正。
通过代码获取当前窗口的工作区域,及任务栏以外的其他区域
System.Windows.SystemParameters.WorkArea.Width获取工作区域的宽
System.Windows.SystemParameters.WorkArea.Height获取工作区域的高
为什么要使用ValueConverter主要是因为WorkArea返回的类型无法直接 binding xaml
<ValueConverters:WorkAreaWidth x:Key="workAreaWidth" />
<ValueConverters:WorkAreaHeight x:Key="workAreaHeight" /><Style x:Key="mainWindow" TargetType="{x:Type Window}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="Window"><ContentControl x:Name="window" Content="{TemplateBinding Content}" /><ControlTemplate.Triggers><Trigger Property="WindowState" Value="Maximized"><Setter TargetName="window" Property="MaxHeight" Value="{Binding Converter={StaticResource workAreaHeight}}" /><Setter TargetName="window" Property="MaxWidth" Value="{Binding Converter={StaticResource workAreaWidth}}" /></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter>
</Style>
using System;
using System.Globalization;
using System.Windows.Data;namespace SignalRClient.ValueConverters
{internal class WorkAreaWidth : IValueConverter{public object Convert(object value, Type targetType, object parameter, CultureInfo culture){return System.Windows.SystemParameters.WorkArea.Width;}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){throw new NotImplementedException();}}
}
using System;
using System.Globalization;
using System.Windows.Data;namespace SignalRClient.ValueConverters
{internal class WorkAreaHeight : IValueConverter{public object Convert(object value, Type targetType, object parameter, CultureInfo culture){return System.Windows.SystemParameters.WorkArea.Height;}public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture){throw new NotImplementedException();}}
}
结语
一开始,确实很难搞,Microsoft 的文档,里面也并没有,详细介绍窗口内容溢出的问题,但是只要仔细研究过 WPF 的同学都知道,很多东西是可以通过
Trigger来实现的。Get 到这一点很多问题就迎刃而解了。欢迎大家留言通过探讨 😃😃😃
相关文章:
【WPF】WindowChrome 自定义窗口完美实现
WindowChrome 自定义窗口完美实现简介效果图自定义最小化、最大化、关闭按钮布局实现结语简介 Microsoft官网关于 WindowChome 的介绍 截取Microsoft文章的一段话: 若要在保留其标准功能时自定义窗口,可以使用该 WindowChrome 类。 该 WindowChrome…...
Python客户端使用SASL_SSL连接Kafka需要将jks密钥转换为pem密钥,需要转化成p12格式再转换pem才能适配confluent_kafka包
证书生成 生成证书以及jks参考以下文章 https://blog.csdn.net/qq_41527073/article/details/121148600 证书转换jks -> pem 需要转化成p12以下转换才能适配confluent_kafka包,直接jks转pem会报错不能使用,具体参考以下文章 https://www.ngui.cc/z…...
JDK8 ConcurrentHashMap源码分析
文章目录常量说明put() 方法putVal() 方法initTable():初始化数组treeifyBin():链表转红黑树tryPresize():初始化数组扩容TreeBin() 构造方法:生成红黑树putTreeVal():往红黑树中插入值helpTransfer():多线…...
前置知识-初值问题、欧拉法、改进欧拉法
1.1 初值问题 初值问题是科研、工程技术应用中最常见的一类问题, 一阶常微分方程的初值问题表述如下: 已知 u ( x ) u(x) u(x) 的起始点 ( x 0 , u 0 ) \left(x_0, u_0\right)...
睡眠影响寿命,这几个睡眠习惯赶紧改掉!
我们知道,现在睡眠不足已经成为普遍问题,但你知道睡眠的时长会影响寿命吗?熬夜对身体不好,已是老生常谈。但睡得过早,也可能影响寿命!2021年《睡眠医学》杂志一项针对21个国家11万名参与者的研究中发现&…...
Linux逻辑卷管理器(PV、VG、LV、PE)
目录 PV阶段 VG阶段 LV阶段 文件系统阶段 逆向操作(删除LVM) 逻辑卷管理器(Logical Volume Manager),简称LVM LVM的做法是将几个物理的分区(或磁盘)通过软件组合成为一块看起来时独立的大…...
Centos7 内核升级
一、背景 在 CentOS 使用过程中,高版本的应用环境可能需要更高版本的内核才能支持,所以难免需要升级内核,所以下面将介绍yum和rpm两种升级内核方式。 关于内核种类: kernel-ml——kernel-ml 中的ml是英文【 mainline stable 】的缩写&…...
SpringBoot 启动配置文件加载和参数配置修改问题
SpringBoot 配置文件修正和参数覆盖SpringBoot 配置文件加载和参数覆盖1、SpringBoot 配置文件加载1.1、修改application.properties的参数几种方式1.2、方法一:直接CMD1.3、方法二:系统变量配置1.4、方法三:程序运行配置1.5、方法四…...
布隆过滤器和布谷鸟过滤器详解
今天和大家分享下布隆过滤器和布谷鸟过滤器 一.布隆过滤器 1.简单介绍 布隆过滤器是用于检索一个元素是否在一个集合中的算法,是一种用空间换时间的查询算法。 2.实现原理 布隆过滤器的存储结构是一个bitmap结构,初始值都是0,如下图所示&am…...
WebGIS前端框架(openlayers,mapbox,leaflet)图形图像底层渲染原理分析
学了这么多的框架,做了这么多的项目,你是否清楚你使用的GIS框架(mapbox,open layers,cesium,leaflet)底层到底是什么原理?是否清楚哪些所谓的地图影像,矢量图形,图标,图像动画等是如何渲染到网页上的?这篇文章就大家解读一下WebGIS的底层原理。 首先说说历史,有时…...
AcWing语法基础课笔记 第五章 C++中的字符串
第五章 C中的字符串 字符串是计算机与人类沟通的重要手段。 ——闫学灿 字符与整数的联系——ASCII码 每个常用字符都对应一个-128~127的数字,二者之间可以相互转化: 常用ASCII值:’A’-‘Z’ 是65~90,’a’-‘z’…...
抓包工具Charles(一)-下载安装与设置
无论是在测试、开发工作中,抓包都是很重要、很常用的技能。Charles作为一款抓包工具,能够满足大部分的工作需求。 文章目录一、下载地址二、安装三、安装根证书(电脑)四、设置五、抓包附录:[零基础入门接口功能测试教程…...
SpringBoot09:Swagger
什么是Swagger? ①是一个API框架 ②可以在线自动生成 RestFul 风格的API文档,实现API文档和API定义同步更新 ③可以直接运行、在线测试 API 接口 ④支持多种语言(Java、PHP等) 官网:API Documentation & Desi…...
Git 常用命令
笔记-git命令1、名词2、基本操作3、分支操作1、名词 master: 默认开发分支origin: 默认远程版本库Index / Stage: 暂存区Workspace: 工作区Repository: 仓库区 (或本地仓库)Remote: 远程仓库 2、基本操作 配置级别 -local (默认,高级优先…...
查看jdk安装路径,在windows上实现多个java jdk的共存解决办法,安装java19后终端乱码的解决
查看jdk安装路径, 在windows上实现多个java jdk的共存解决办法, 安装java19后终端乱码的解决 目录 一、查看jdk(java开发工具包)安装路径的方法 二、在windows上实现多个java jdk的共存 (1)、安装好多…...
链表数据结构
用途: 链表是一种用于计算机中存储与组织数据的结构,链表将数据以节点的形式串联起来,其存储的容量大小可以动态伸缩。 结构: typedef struct {int data; /*当前节点的数据*/node *next;/*下一个节点的指针*/node *last;/*上一个…...
汽车DTC故障内码与标准故障码的解析与转换
目录 一、故障内码与标准故障码的解析 (1)故障内码的信息格式与解析 (2)故障内码中DTC状态的解析 (3)故障内码与标准故障码之间的对应关系 二、故障内码与标准故障码的转换代码 一、故障内码与标准故障…...
零基础学习测试还是开发?
软件测试作为IT行业的刚需职位,其实是非常适合0基础的小白同学加入学习的但是具体选择测试还是开发还是要看你个人的兴趣爱好以及学习能力,对哪个感兴趣,哪个能学的会就选择哪个就可以了 平时说起程序员印象中大都是做Java、做前端、做后端&…...
如何加入new bing候补名单
如何加入new bing候补名单 我们都知道现在最新版edges中已经提示我们可以加入new bing候补名单,但国内环境下无法正常加入new bing候补名单,这篇文章讲告诉你如何绕过限制加入new bing候补名单 下载配置 HeaderEditor 插件 下载地址microsoftedge.mic…...
中国天气——西风带环流和寒潮
中国天气——西风带环流和寒潮 一. 西风环流概述 1. 概念 西风带:中高纬度地区平均水平环流在对流层盛行西风,称之为西风带西风带波动:西风带围绕极涡沿纬圈运动,平均而言表现为冬季三槽三脊,夏季四槽四脊ÿ…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
鸿蒙DevEco Studio HarmonyOS 5跑酷小游戏实现指南
1. 项目概述 本跑酷小游戏基于鸿蒙HarmonyOS 5开发,使用DevEco Studio作为开发工具,采用Java语言实现,包含角色控制、障碍物生成和分数计算系统。 2. 项目结构 /src/main/java/com/example/runner/├── MainAbilitySlice.java // 主界…...
laravel8+vue3.0+element-plus搭建方法
创建 laravel8 项目 composer create-project --prefer-dist laravel/laravel laravel8 8.* 安装 laravel/ui composer require laravel/ui 修改 package.json 文件 "devDependencies": {"vue/compiler-sfc": "^3.0.7","axios": …...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
Rust 开发环境搭建
环境搭建 1、开发工具RustRover 或者vs code 2、Cygwin64 安装 https://cygwin.com/install.html 在工具终端执行: rustup toolchain install stable-x86_64-pc-windows-gnu rustup default stable-x86_64-pc-windows-gnu 2、Hello World fn main() { println…...
