将已知大小转换为设备像素
如果您的可视元素已附加到 PresentationSource(例如,它是屏幕上可见的窗口的一部分),则可以通过以下方式找到转换:
var source = PresentationSource.FromVisual(element);
Matrix transformToDevice = source.CompositionTarget.TransformToDevice;
如果没有,请使用 HwndSource 创建一个临时 hWnd:
Matrix transformToDevice;
using(var source = new HwndSource(new HwndSourceParameters()))
transformToDevice = source.CompositionTarget.TransformToDevice;
请注意,这比使用 IntPtr.Zero 的 hWnd 构建效率低,但我认为它更可靠,因为由 HwndSource 创建的 hWnd 将与实际新创建的 Window 连接到相同的显示设备。这样,如果不同的显示设备具有不同的 DPI,您肯定会获得正确的 DPI 值。
完成转换后,您可以将任何大小从 WPF 大小转换为像素大小:
var pixelSize = (Size)transformToDevice.Transform((Vector)wpfSize);
将像素大小转换为整数
如果要将像素大小转换为整数,只需执行以下操作:
int pixelWidth = (int)pixelSize.Width;
int pixelHeight = (int)pixelSize.Height;
但更强大的解决方案将是 ElementHost 使用的解决方案:
int pixelWidth = (int)Math.Max(int.MinValue, Math.Min(int.MaxValue, pixelSize.Width));
int pixelHeight = (int)Math.Max(int.MinValue, Math.Min(int.MaxValue, pixelSize.Height));
获取所需的 UIElement 大小
要获得所需的 UIElement 大小,您需要确保对其进行测量。在某些情况下,它已经被测量过了,或者是因为:
- 你已经测量过了
- 你测量了它的祖先之一,或者
- 它是 PresentationSource 的一部分(例如,它在可见窗口中)并且您在 DispatcherPriority.Render 下面执行,因此您知道测量已经自动发生。
如果您的视觉元素尚未被测量,您应该在控件或其祖先之一上调用 Measure ,传入可用的大小(或者new Size(double.PositivieInfinity, double.PositiveInfinity)
如果您想调整内容的大小:
element.Measure(availableSize);
测量完成后,只需使用矩阵转换 DesiredSize:
var pixelSize = (Size)transformToDevice.Transform((Vector)element.DesiredSize);
把它们放在一起
这是一个简单的方法,展示了如何获取元素的像素大小:
public Size GetElementPixelSize(UIElement element)
{
Matrix transformToDevice;
var source = PresentationSource.FromVisual(element);
if(source!=null)
transformToDevice = source.CompositionTarget.TransformToDevice;
else
using(var source = new HwndSource(new HwndSourceParameters()))
transformToDevice = source.CompositionTarget.TransformToDevice;
if(element.DesiredSize == new Size())
element.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
return (Size)transformToDevice.Transform((Vector)element.DesiredSize);
}
请注意,在此代码中,仅当不存在 DesiredSize 时才调用 Measure。这提供了一种方便的方法来做所有事情,但有几个缺陷:
- 元素的父元素可能会传入较小的可用大小
- 如果实际 DesiredSize 为零(重复重新测量),则效率低下
- 它可能会以某种方式掩盖错误,从而导致应用程序由于意外时间而失败(例如,在 DispatchPriority.Render 或以上调用的代码)
由于这些原因,我倾向于省略 GetElementPixelSize 中的 Measure 调用,而让客户端执行此操作。