当前位置: 首页 > news >正文

【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文章的一段话&#xff1a;   若要在保留其标准功能时自定义窗口&#xff0c;可以使用该 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包&#xff0c;直接jks转pem会报错不能使用&#xff0c;具体参考以下文章 https://www.ngui.cc/z…...

JDK8 ConcurrentHashMap源码分析

文章目录常量说明put() 方法putVal() 方法initTable()&#xff1a;初始化数组treeifyBin()&#xff1a;链表转红黑树tryPresize()&#xff1a;初始化数组扩容TreeBin() 构造方法&#xff1a;生成红黑树putTreeVal()&#xff1a;往红黑树中插入值helpTransfer()&#xff1a;多线…...

前置知识-初值问题、欧拉法、改进欧拉法

1.1 初值问题 初值问题是科研、工程技术应用中最常见的一类问题, 一阶常微分方程的初值问题表述如下: 已知 u ( x ) u(x) u(x) 的起始点 ( x 0 , u 0 ) \left(x_0, u_0\right)...

睡眠影响寿命,这几个睡眠习惯赶紧改掉!

我们知道&#xff0c;现在睡眠不足已经成为普遍问题&#xff0c;但你知道睡眠的时长会影响寿命吗&#xff1f;熬夜对身体不好&#xff0c;已是老生常谈。但睡得过早&#xff0c;也可能影响寿命&#xff01;2021年《睡眠医学》杂志一项针对21个国家11万名参与者的研究中发现&…...

Linux逻辑卷管理器(PV、VG、LV、PE)

目录 PV阶段 VG阶段 LV阶段 文件系统阶段 逆向操作&#xff08;删除LVM&#xff09; 逻辑卷管理器&#xff08;Logical Volume Manager&#xff09;&#xff0c;简称LVM LVM的做法是将几个物理的分区&#xff08;或磁盘&#xff09;通过软件组合成为一块看起来时独立的大…...

Centos7 内核升级

一、背景 在 CentOS 使用过程中&#xff0c;高版本的应用环境可能需要更高版本的内核才能支持&#xff0c;所以难免需要升级内核&#xff0c;所以下面将介绍yum和rpm两种升级内核方式。 关于内核种类: kernel-ml——kernel-ml 中的ml是英文【 mainline stable 】的缩写&…...

SpringBoot 启动配置文件加载和参数配置修改问题

SpringBoot 配置文件修正和参数覆盖SpringBoot 配置文件加载和参数覆盖1、SpringBoot 配置文件加载1.1、修改application.properties的参数几种方式1.2、方法一&#xff1a;直接CMD1.3、方法二&#xff1a;系统变量配置1.4、方法三&#xff1a;程序运行配置1.5、方法四&#xf…...

布隆过滤器和布谷鸟过滤器详解

今天和大家分享下布隆过滤器和布谷鸟过滤器 一.布隆过滤器 1.简单介绍 布隆过滤器是用于检索一个元素是否在一个集合中的算法&#xff0c;是一种用空间换时间的查询算法。 2.实现原理 布隆过滤器的存储结构是一个bitmap结构&#xff0c;初始值都是0&#xff0c;如下图所示&am…...

WebGIS前端框架(openlayers,mapbox,leaflet)图形图像底层渲染原理分析

学了这么多的框架,做了这么多的项目,你是否清楚你使用的GIS框架(mapbox,open layers,cesium,leaflet)底层到底是什么原理?是否清楚哪些所谓的地图影像,矢量图形,图标,图像动画等是如何渲染到网页上的?这篇文章就大家解读一下WebGIS的底层原理。 首先说说历史,有时…...

AcWing语法基础课笔记 第五章 C++中的字符串

第五章 C中的字符串 字符串是计算机与人类沟通的重要手段。 ——闫学灿 字符与整数的联系——ASCII码 每个常用字符都对应一个-128~127的数字&#xff0c;二者之间可以相互转化&#xff1a; 常用ASCII值&#xff1a;’A’-‘Z’ 是65~90&#xff0c;’a’-‘z’…...

抓包工具Charles(一)-下载安装与设置

无论是在测试、开发工作中&#xff0c;抓包都是很重要、很常用的技能。Charles作为一款抓包工具&#xff0c;能够满足大部分的工作需求。 文章目录一、下载地址二、安装三、安装根证书&#xff08;电脑&#xff09;四、设置五、抓包附录&#xff1a;[零基础入门接口功能测试教程…...

SpringBoot09:Swagger

什么是Swagger&#xff1f; ①是一个API框架 ②可以在线自动生成 RestFul 风格的API文档&#xff0c;实现API文档和API定义同步更新 ③可以直接运行、在线测试 API 接口 ④支持多种语言&#xff08;Java、PHP等&#xff09; 官网&#xff1a;API Documentation & Desi…...

Git 常用命令

笔记-git命令1、名词2、基本操作3、分支操作1、名词 master: 默认开发分支origin: 默认远程版本库Index / Stage: 暂存区Workspace: 工作区Repository: 仓库区 &#xff08;或本地仓库&#xff09;Remote: 远程仓库 2、基本操作 配置级别 -local (默认&#xff0c;高级优先…...

查看jdk安装路径,在windows上实现多个java jdk的共存解决办法,安装java19后终端乱码的解决

查看jdk安装路径&#xff0c; 在windows上实现多个java jdk的共存解决办法&#xff0c; 安装java19后终端乱码的解决 目录 一、查看jdk&#xff08;java开发工具包&#xff09;安装路径的方法 二、在windows上实现多个java jdk的共存 &#xff08;1&#xff09;、安装好多…...

链表数据结构

用途&#xff1a; 链表是一种用于计算机中存储与组织数据的结构&#xff0c;链表将数据以节点的形式串联起来&#xff0c;其存储的容量大小可以动态伸缩。 结构&#xff1a; typedef struct {int data; /*当前节点的数据*/node *next;/*下一个节点的指针*/node *last;/*上一个…...

汽车DTC故障内码与标准故障码的解析与转换

目录 一、故障内码与标准故障码的解析 &#xff08;1&#xff09;故障内码的信息格式与解析 &#xff08;2&#xff09;故障内码中DTC状态的解析 &#xff08;3&#xff09;故障内码与标准故障码之间的对应关系 二、故障内码与标准故障码的转换代码 一、故障内码与标准故障…...

零基础学习测试还是开发?

软件测试作为IT行业的刚需职位&#xff0c;其实是非常适合0基础的小白同学加入学习的但是具体选择测试还是开发还是要看你个人的兴趣爱好以及学习能力&#xff0c;对哪个感兴趣&#xff0c;哪个能学的会就选择哪个就可以了 平时说起程序员印象中大都是做Java、做前端、做后端&…...

如何加入new bing候补名单

如何加入new bing候补名单 我们都知道现在最新版edges中已经提示我们可以加入new bing候补名单&#xff0c;但国内环境下无法正常加入new bing候补名单&#xff0c;这篇文章讲告诉你如何绕过限制加入new bing候补名单 下载配置 HeaderEditor 插件 下载地址microsoftedge.mic…...

中国天气——西风带环流和寒潮

中国天气——西风带环流和寒潮 一. 西风环流概述 1. 概念 西风带&#xff1a;中高纬度地区平均水平环流在对流层盛行西风&#xff0c;称之为西风带西风带波动&#xff1a;西风带围绕极涡沿纬圈运动&#xff0c;平均而言表现为冬季三槽三脊&#xff0c;夏季四槽四脊&#xff…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合

强化学习&#xff08;Reinforcement Learning, RL&#xff09;是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程&#xff0c;然后使用强化学习的Actor-Critic机制&#xff08;中文译作“知行互动”机制&#xff09;&#xff0c;逐步迭代求解…...

Python:操作 Excel 折叠

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...

LeetCode - 394. 字符串解码

题目 394. 字符串解码 - 力扣&#xff08;LeetCode&#xff09; 思路 使用两个栈&#xff1a;一个存储重复次数&#xff0c;一个存储字符串 遍历输入字符串&#xff1a; 数字处理&#xff1a;遇到数字时&#xff0c;累积计算重复次数左括号处理&#xff1a;保存当前状态&a…...

linux arm系统烧录

1、打开瑞芯微程序 2、按住linux arm 的 recover按键 插入电源 3、当瑞芯微检测到有设备 4、松开recover按键 5、选择升级固件 6、点击固件选择本地刷机的linux arm 镜像 7、点击升级 &#xff08;忘了有没有这步了 估计有&#xff09; 刷机程序 和 镜像 就不提供了。要刷的时…...

Psychopy音频的使用

Psychopy音频的使用 本文主要解决以下问题&#xff1a; 指定音频引擎与设备&#xff1b;播放音频文件 本文所使用的环境&#xff1a; Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/

使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题&#xff1a;docker pull 失败 网络不同&#xff0c;需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...

数据库分批入库

今天在工作中&#xff0c;遇到一个问题&#xff0c;就是分批查询的时候&#xff0c;由于批次过大导致出现了一些问题&#xff0c;一下是问题描述和解决方案&#xff1a; 示例&#xff1a; // 假设已有数据列表 dataList 和 PreparedStatement pstmt int batchSize 1000; // …...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

Mysql8 忘记密码重置,以及问题解决

1.使用免密登录 找到配置MySQL文件&#xff0c;我的文件路径是/etc/mysql/my.cnf&#xff0c;有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...