| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105 |
- using System;
- using System.Collections.Generic;
- using System.Windows;
- using System.Windows.Media;
- using Microsoft.Win32;
- namespace TeamAAS
- {
- /// <summary>
- /// 窗口分辨率/DPI 自适应助手。
- /// </summary>
- public static class UiScaler
- {
- private static double _globalScale = 1.0;
- /// <summary>当前全局缩放因子(弹窗读取用)</summary>
- public static double GlobalScale => _globalScale;
- /// <summary>全局因子变化通知(弹窗订阅后自动跟随)</summary>
- public static event Action ScaleChanged;
- private static readonly Dictionary<Window, Size> _designSizes = new Dictionary<Window, Size>();
- /// <summary>
- /// 主窗口:计算全局缩放因子并应用(设计基准默认 1600x900,钳制 minScale~maxScale)。
- /// </summary>
- public static void AttachMain(Window window, double refWidth = 1600, double refHeight = 900,
- double minScale = 0.6, double maxScale = 2.0)
- {
- if (window == null) return;
- var root = window.Content as FrameworkElement;
- if (root == null) return;
- if (root.Tag is UiScalerToken) return;
- root.Tag = new UiScalerToken();
- void Update()
- {
- double w = window.ActualWidth > 0 ? window.ActualWidth : refWidth;
- double h = window.ActualHeight > 0 ? window.ActualHeight : refHeight;
- double f = Math.Min(w / refWidth, h / refHeight);
- _globalScale = Math.Max(minScale, Math.Min(maxScale, f));
- ApplyTransform(window, _globalScale, resizeWindow: false);
- ScaleChanged?.Invoke();
- }
- window.SizeChanged += (s, e) => Update();
- window.DpiChanged += (s, e) => Update();
- window.Loaded += (s, e) => Update();
- SystemEvents.DisplaySettingsChanged += (s, e) => window.Dispatcher.Invoke(Update);
- }
- /// <summary>
- /// 弹窗/子窗体:跟随全局缩放因子(只放大不缩小,窗口尺寸与内容同步缩放)。
- /// 幂等:重复调用/全局钩子叠加均安全。
- /// </summary>
- public static void Attach(Window window)
- {
- if (window == null) return;
- var root = window.Content as FrameworkElement;
- if (root == null) return;
- if (root.Tag is UiScalerToken) return;
- root.Tag = new UiScalerToken();
- Action apply = () => ApplyTransform(window, _globalScale, resizeWindow: true);
- apply();
- // 全局因子变化时跟随;关闭时退订,避免事件泄漏
- ScaleChanged += apply;
- window.Closed += (s, e) => ScaleChanged -= apply;
- }
- private static void ApplyTransform(Window w, double f, bool resizeWindow)
- {
- var root = w.Content as FrameworkElement;
- if (root == null) return;
- // 弹窗只放大不缩小(f<1 时保持 1.0,避免小窗被缩到看不清)
- double effective = resizeWindow ? Math.Max(1.0, f) : f;
- if (Math.Abs(effective - 1.0) < 0.001)
- {
- root.LayoutTransform = null;
- return;
- }
- if (resizeWindow)
- {
- // 首次记录设计尺寸(XAML 声明值;NaN=自动/SizeToContent 交由内容自适应)
- if (!_designSizes.TryGetValue(w, out var design))
- {
- design = new Size(w.Width, w.Height);
- _designSizes[w] = design;
- }
- if (!double.IsNaN(design.Width) && design.Width > 0) w.Width = design.Width * effective;
- if (!double.IsNaN(design.Height) && design.Height > 0) w.Height = design.Height * effective;
- }
- root.LayoutTransform = new ScaleTransform(effective, effective);
- }
- private sealed class UiScalerToken { }
- }
- }
|