Created
April 25, 2019 09:21
-
-
Save walterlv/6015ea19c9338b9e45ca053b102cf456 to your computer and use it in GitHub Desktop.
Calculate WPF visual scaling ratios to user monitor device.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Windows; | |
using System.Windows.Media; | |
namespace Walterlv | |
{ | |
public static class VisualScalingExtensions | |
{ | |
/// <summary> | |
/// 获取一个 <paramref name="visual"/> 在显示设备上的尺寸相对于自身尺寸的缩放比。 | |
/// </summary> | |
public static Size GetScalingRatioToDevice(this Visual visual) | |
{ | |
return visual.GetTransformInfoToDevice().size; | |
} | |
/// <summary> | |
/// 获取一个 <paramref name="visual"/> 在显示设备上的尺寸相对于自身尺寸的缩放比和旋转角度(顺时针为正角度)。 | |
/// </summary> | |
public static (Size size, double angle) GetTransformInfoToDevice(this Visual visual) | |
{ | |
if (visual == null) throw new ArgumentNullException(nameof(visual)); | |
// 计算此 Visual 在 WPF 窗口内部的缩放(含 ScaleTransform 等)。 | |
var root = VisualRoot(visual); | |
var transform = ((MatrixTransform)visual.TransformToAncestor(root)).Value; | |
// 计算此 WPF 窗口相比于设备的外部缩放(含 DPI 缩放等)。 | |
var ct = PresentationSource.FromVisual(visual)?.CompositionTarget; | |
if (ct != null) | |
{ | |
transform.Append(ct.TransformToDevice); | |
} | |
// 如果元素有旋转,则计算旋转分量。 | |
var unitVector = new Vector(1, 0); | |
var vector = transform.Transform(unitVector); | |
var angle = Vector.AngleBetween(unitVector, vector); | |
transform.Rotate(-angle); | |
// 计算考虑了旋转的综合缩放比。 | |
var rect = new Rect(new Size(1, 1)); | |
rect.Transform(transform); | |
return (rect.Size, angle); | |
} | |
/// <summary> | |
/// 寻找一个 <see cref="Visual"/> 连接着的视觉树的根。 | |
/// 通常,如果这个 <see cref="Visual"/> 显示在窗口中,则根为 <see cref="Window"/>; | |
/// 不过,如果此 <see cref="Visual"/> 没有显示出来,则根为某一个包含它的 <see cref="Visual"/>。 | |
/// 如果此 <see cref="Visual"/> 未连接到任何其它 <see cref="Visual"/>,则根为它自身。 | |
/// </summary> | |
private static Visual VisualRoot(Visual visual) | |
{ | |
if (visual == null) throw new ArgumentNullException(nameof(visual)); | |
var root = visual; | |
var parent = VisualTreeHelper.GetParent(visual); | |
while (parent != null) | |
{ | |
if (parent is Visual r) | |
{ | |
root = r; | |
} | |
parent = VisualTreeHelper.GetParent(parent); | |
} | |
return root; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment