从零开始编写一个办公软件(二、自适应窗口)

news/2025/10/29 23:08:56/文章来源:https://www.cnblogs.com/yy250/p/19175588

桌面开发通常需要面对因为屏幕大小不同产生的视觉过大或过小的问题,基本都会被要求做大小自适应处理。网上一般介绍的是ViewBox,简单方便,但不仅面临性能的问题,部分情况下还会出现UI失真。我这里介绍下更繁琐但实用的方法,虽然开发起来麻烦不少,但运行效果会好很多。
首先建立一个资源字典,把所有和尺寸相关的数值都放进这个字典文件中,举个例子:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:sys="clr-namespace:System;assembly=netstandard" xmlns:m="http://schemas.microsoft.com/netfx/2009/xaml/presentation"><!--#region Double--><sys:Double x:Key="D_1d5">1.5</sys:Double><sys:Double x:Key="D_2">2</sys:Double><sys:Double x:Key="D_8">8</sys:Double><sys:Double x:Key="D_30">30</sys:Double><sys:Double x:Key="D_45">45</sys:Double><sys:Double x:Key="D_48">48</sys:Double><sys:Double x:Key="D_640">640</sys:Double><sys:Double x:Key="D_960">960</sys:Double><!--#endregion--><!--#region Thickness--><m:Thickness x:Key="T_1d5">1.5</m:Thickness><m:Thickness x:Key="T_2">2</m:Thickness><m:Thickness x:Key="T_7">7</m:Thickness><m:Thickness x:Key="T_0_48_0_0">0 48 0 0</m:Thickness><!--#endregion--><!--#region Geometry--><m:Geometry x:Key="MinimizeButtonGeometry">M0,0 12,0</m:Geometry><m:Geometry x:Key="MaximizeButtonGeometry1">M0,0 12,0 12,10 0,10 z</m:Geometry><m:Geometry x:Key="MaximizeButtonGeometry2">M0,3 0,12 9,12 9,3 z M3,3 3,0 12,0 12,9 9,9</m:Geometry><m:Geometry x:Key="CloseButtonGeometry">M0,0 12,12 M12,0 0,12</m:Geometry><!--#endregion--><!--#region CornerRadius--><m:CornerRadius x:Key="CR_8">8</m:CornerRadius><!--#endregion-->
</ResourceDictionary>

然后是重点,千万不要在xaml里引用这个字典!
考虑到开发过程当中的设计问题,可以这么写:

<Window x:Class="LkWork.WPF.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:LkWork.WPF"mc:Ignorable="d" WindowStartupLocation="CenterScreen"Title="MainWindow" Height="{DynamicResource D_640}" Width="{DynamicResource D_960}"><Window.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><d:ResourceDictionary Source="pack://application:,,,/LkWork.WPF;component/Resources/Styles/WindowSizeStyles.xaml"/></ResourceDictionary.MergedDictionaries></ResourceDictionary></Window.Resources><Grid></Grid>
</Window>

在ResourceDictionary前面加上d:,既不影响使用,又比较方便开发。

然后开始使用了,打开App.xaml.cs文件,替换代码

using Microsoft.Win32;
using System.Configuration;
using System.Data;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;namespace LkWork.WPF
{/// <summary>/// Interaction logic for App.xaml/// </summary>public partial class App : Application{protected override void OnStartup(StartupEventArgs e){//监听显示设置变化事件SystemEvents.DisplaySettingsChanging += SystemEvents_DisplaySettingsChanging;InitializeAppSize();base.OnStartup(e);}private double WindowScale = 1;private void SystemEvents_DisplaySettingsChanging(object? sender, EventArgs e){InitializeAppSize();}private void InitializeAppSize(){ResourceDictionary resource = new ResourceDictionary() { Source = new Uri("pack://application:,,,/LkWork.WPF;component/Resources/Styles/WindowSizeStyles.xaml", UriKind.Absolute) };var firstKey = resource.Keys.Cast<string>().First();double scale = Math.Max(SystemParameters.PrimaryScreenWidth / 1920, SystemParameters.PrimaryScreenHeight / 1080);if (firstKey is not null){if (Math.Abs(scale - WindowScale) > 0.1) return; //缩放比例没有变化则不处理var old = this.Resources.MergedDictionaries.Where(x => x.Contains(firstKey)).FirstOrDefault();if (old is not null) this.Resources.MergedDictionaries.Remove(old);}//缩放比例有比较明显的变化,需要调整资源中的数值if (Math.Abs(scale - WindowScale) > 0.1){foreach (var key in resource.Keys.Cast<string>()){var value = resource[key];if (value is double d){resource.Remove(key);resource.Add(key, d * scale);}else if (value is Thickness t){resource.Remove(key);resource.Add(key, new Thickness(t.Left * scale, t.Top * scale, t.Right * scale, t.Bottom * scale));}else if (value is CornerRadius c){resource.Remove(key);resource.Add(key, new CornerRadius(c.TopLeft * scale, c.TopRight * scale, c.BottomRight * scale, c.BottomLeft * scale));}else if(value is Geometry g){g = g.Clone();g.Transform = new ScaleTransform(scale, scale, 0, 0);g.Freeze();resource.Remove(key);resource.Add(key, g);}}//窗口大小需要额外调整foreach (Window window in this.Windows){if (!double.IsNaN(window.Width)) window.Width *= scale / WindowScale;if (!double.IsNaN(window.Height)) window.Height *= scale / WindowScale;}}this.Resources.MergedDictionaries.Add(resource);WindowScale = scale;}}}

运行代码,调整显示缩放查看效果
image
我这里是成功更改大小了的,收工。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/950316.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

10月29日日记

1.今天学习马哲以及;离散数学。 2.明天上体育课 3.Redis为什么使用跳跃表而不是平衡树?

2025.10.29总结

那个心理咨询项目学习模块完成学习包的添加和展示,还有完成进度的展示。后续需要为学习包添加视频,测验,测验后生成报告

代码大全2,阅读1

“编程是手艺,更是态度” 的表述,又让我沉下心来读。最先锁定第 33 章 “个人性格”,是因为很好奇:为什么一本讲代码的书,会把 “性格” 放在重要位置?读完才发现,作者把 “程序员该有的特质” 拆解得既具体又透…

代码大全2,阅读2

“布局清晰、控制逻辑严谨”,才是 “好代码” 的标配。但过程中也有不少和作者观点 “碰撞” 的地方,反而让思考更深入。 先说说 “数据声明的布局”。作者提了三个核心建议:每行只声明一个变量、变量声明贴近首次使…

UNIQUE VISION Programming Contest 2024 Christmas (AtCoder Beginner Contest 385)

D - Santa Claus 2 map<int,set> E - Snowflake Tree 开始想到枚举中心点,x=度数,y=min儿子度数-1,其余全要删除,删除越少留下越多,留下1+x+xy,删n-(1+x+xy) 样例1告诉我们可以删除某个子树,这样还是y=min儿…

如果我想在项目发布后,动态更新组件,如何使用模块联邦实现?

要在项目发布后动态更新组件,并使用 Webpack Module Federation(模块联邦) 实现,核心思路是: 将组件拆分为独立的 Remote 应用,Host 应用在运行时从远程加载最新版本的组件,而无需重新构建或部署 Host。 这正是…

静态类型、动态类型、强类型、弱类型

静态类型、动态类型、强类型、弱类型 静态类型与动态类型 变量类型是否会随赋值变化——何时确定变量的类型。静态类型:代码中需要指定变量的类型(或者自动推导),编译期就进行类型检查,无须运行代码即可确定变量的…

AI浪潮下的职业迷思:机遇还是泡沫?

最近刷到一堆AI新闻,从创业融资到巨头裁员,感觉整个行业像坐过山车。一边是剪映前产品负责人廖谦离职创业,半个月就拿下几百万美元投资,搞多模态Agent;另一边Meta却在清晨五点发裁员邮件,连工作十几年的AI科学家…

10/29

dota2水平更上一层lou,冠绝局把把c,就是恐怖利刃太吃队友了,不一定能打好。今天预备学习了tomcat配置 und 离散数学111

[Docker] Docker拉取镜像url详解

[Docker] Docker拉取镜像url详解$(".postTitle2").removeClass("postTitle2").addClass("singleposttitle");目录完整命令简化版本 完整命令 # docker - Docker 客户端命令行工具,用于…

activemqCVE-2015-5254漏洞复现

activemq/CVE-2015-5254漏洞复现 原理 该漏洞源于序列化的Java Message Service(JMS)ObjectMessage对象存在反序列化漏洞,同时程序没有对代理中序列化的类做限制,导致攻击者可以构造恶意的序列化的类进行RCE攻击。 影…

模块联邦共享组件的时候如何进行版本管理

在使用 Webpack Module Federation(模块联邦) 共享组件时,版本管理 是一个关键挑战。 因为微前端或微组件架构中,多个应用(Host 和 Remotes)可能由不同团队维护、独立部署,若组件版本不一致,极易导致运行时错误…

查询排序与表连接

一、分组(group by)相关 (一)分组(group by)的作用 按逻辑次序合并具有重复值的字段,用于查看指定分组的聚合情况,查询结果可同时包含普通列和聚合函数(如 avg、max、min、count 等)。 (二)分组与过滤的语…

pyqt 自定义QTableWidget

自定义QTableWidget `import sys from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QWidget, QComboBox, QTabWidget, QTableWidget, QTableWidgetItem) from PyQt5.QtCore import Qt import re…

价值主体的技术实现:基于Free Transformer潜变量Z的AI元人文架构探索

基于Free Transformer的潜变量Z技术探索"价值主体行为"时,岐金兰揭示的两个核心担忧,指出了理论技术化过程中的关键风险。这些风险若不能得到妥善解决,将导致AI元人文构想从生机勃勃的价值生态系统,蜕变…

第二十二天

《程序员修炼之道:从小工到专家》阅读笔记:思维重塑 在技术迭代如浪潮的行业里,这本书并非罗列API的工具书,而是为程序员搭建了从“完成任务”到“创造价值”的思维桥梁。它最核心的启示在于:优秀的程序员,本质是…

Problemsetting

List of my problems其实我很不会出题, 所以不会常更新可能不会更新.Problem Difficulty[集训队互测 2023] 优惠购物 3300【UER #12】电子运动 2800【UNR #9】星图 2800【UNR #9】Sing 2900Canvas Painting ?cooperat…

记录一下我最近一年写的脚本,不知不觉近100个了!

记录一下我最近一年写的脚本,不知不觉近100个了! 一个系统初始化的脚本 @echo offecho 右击鼠标以管理员身份运行,按任意键退出 echo 开启远程桌面连接Wmic OS Get Caption | Findstr /i "7" >nul …

The 2025 Hunan Collegiate Programming Contest

Preface 不知道 VP 什么就找了场 QOJ 上最新的比赛,结果发现打的时候就我们一个队,全程无榜就很难受 而且这场的题目质量确实让人不敢恭维,一堆原题和典题,基本没有那种有意思的思维题 最后 9 of 11,剩下两个感觉…

List of my problems

其实我很不会出题, 所以不会常更新.Problem Difficulty[集训队互测 2023] 优惠购物 3300【UER #12】电子运动 2800【UNR #9】星图 2800【UNR #9】Sing 2900Canvas Painting ?cooperated (modified solution/idea):Pr…