using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using Microsoft.Win32;
namespace TeamAAS
{
///
/// 窗口分辨率/DPI 自适应助手。
///
public static class UiScaler
{
private static double _globalScale = 1.0;
/// 当前全局缩放因子(弹窗读取用)
public static double GlobalScale => _globalScale;
/// 全局因子变化通知(弹窗订阅后自动跟随)
public static event Action ScaleChanged;
private static readonly Dictionary _designSizes = new Dictionary();
///
/// 主窗口:计算全局缩放因子并应用(设计基准默认 1600x900,钳制 minScale~maxScale)。
///
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);
}
///
/// 弹窗/子窗体:跟随全局缩放因子(只放大不缩小,窗口尺寸与内容同步缩放)。
/// 幂等:重复调用/全局钩子叠加均安全。
///
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 { }
}
}