Joe*_*ite 36 wpf dpi elementhost
将WPF(与分辨率无关的)宽度和高度转换为物理屏幕像素的最佳方法是什么?
我在WinForms表单中显示WPF内容(通过ElementHost),并试图找出一些大小调整逻辑.当操作系统以默认的96 dpi运行时,我的工作正常.但是当操作系统设置为120 dpi或其他分辨率时,它将无法工作,因为就WinForms而言,报告其宽度为96的WPF元素实际上将是120像素宽.
我在System.Windows.SystemParameters上找不到任何"每英寸像素数"设置.我确信我可以使用WinForms等效(System.Windows.Forms.SystemInformation),但是有更好的方法吗(阅读:使用WPF API的方式,而不是使用WinForms API并手动进行数学运算)?将WPF"像素"转换为真实屏幕像素的"最佳方法"是什么?
编辑:我也希望在屏幕上显示WPF控件之前执行此操作.看起来像Visual.PointToScreen可以给我正确的答案,但我不能使用它,因为控件还没有父级,我得到InvalidOperationException"这个Visual没有连接到PresentationSource".
Ray*_*rns 63
将已知大小转换为设备像素
如果您的可视元素已经附加到PresentationSource(例如,它是屏幕上可见的窗口的一部分),则可以通过以下方式找到转换:
var source = PresentationSource.FromVisual(element);
Matrix transformToDevice = source.CompositionTarget.TransformToDevice;
Run Code Online (Sandbox Code Playgroud)
如果没有,请使用HwndSource创建临时hWnd:
Matrix transformToDevice;
using(var source = new HwndSource(new HwndSourceParameters()))
transformToDevice = source.TransformToDevice;
Run Code Online (Sandbox Code Playgroud)
请注意,这比使用hWnd的IntPtr.Zero构建效率低,但我认为它更可靠,因为HwndSource创建的hWnd将附加到与实际新创建的Window相同的显示设备上.这样,如果不同的显示设备具有不同的DPI,您肯定会获得正确的DPI值.
完成转换后,您可以将任何大小从WPF大小转换为像素大小:
var pixelSize = (Size)transformToDevice.Transform((Vector)wpfSize);
Run Code Online (Sandbox Code Playgroud)
将像素大小转换为整数
如果要将像素大小转换为整数,您可以简单地执行以下操作:
int pixelWidth = (int)pixelSize.Width;
int pixelHeight = (int)pixelSize.Height;
Run Code Online (Sandbox Code Playgroud)
但更强大的解决方案将是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));
Run Code Online (Sandbox Code Playgroud)
获得所需的UIElement大小
要获得所需的UIElement大小,您需要确保测量它.在某些情况下,它已经被测量,或者是因为:
如果尚未测量您的视觉元素,您应该在控件或其中一个祖先上调用Measure,传递可用的大小(或者new Size(double.PositivieInfinity, double.PositiveInfinity)
如果您想要调整内容大小:
element.Measure(availableSize);
Run Code Online (Sandbox Code Playgroud)
测量完成后,只需使用矩阵转换DesiredSize即可:
var pixelSize = (Size)transformToDevice.Transform((Vector)element.DesiredSize);
Run Code Online (Sandbox Code Playgroud)
把它们放在一起
这是一个简单的方法,显示如何获取元素的像素大小:
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);
}
Run Code Online (Sandbox Code Playgroud)
请注意,在此代码中,如果不存在DesiredSize,则仅调用Measure.这提供了一种方便的方法来完成所有事情,但有几个不足之处:
由于这些原因,我倾向于省略GetElementPixelSize中的Measure调用,只是让客户端执行它.
我找到了一种方法,但我不喜欢它:
using (var graphics = Graphics.FromHwnd(IntPtr.Zero))
{
var pixelWidth = (int) (element.DesiredSize.Width * graphics.DpiX / 96.0);
var pixelHeight = (int) (element.DesiredSize.Height * graphics.DpiY / 96.0);
// ...
}
Run Code Online (Sandbox Code Playgroud)
我不喜欢它,因为(a)它需要引用System.Drawing,而不是使用WPF API; (b)我必须自己做数学,这意味着我正在重复WPF的实现细节.在.NET 3.5中,我必须截断计算结果以匹配ElementHost与AutoSize = true的作用,但我不知道在未来的.NET版本中这是否仍然准确.
这似乎有效,所以我发布它以防万一它帮助其他人.但如果有人有更好的答案,请发布.
Screen.WorkingArea和SystemParameters.WorkArea之间的比例很简单:
private double PointsToPixels (double wpfPoints, LengthDirection direction)
{
if (direction == LengthDirection.Horizontal)
{
return wpfPoints * Screen.PrimaryScreen.WorkingArea.Width / SystemParameters.WorkArea.Width;
}
else
{
return wpfPoints * Screen.PrimaryScreen.WorkingArea.Height / SystemParameters.WorkArea.Height;
}
}
private double PixelsToPoints(int pixels, LengthDirection direction)
{
if (direction == LengthDirection.Horizontal)
{
return pixels * SystemParameters.WorkArea.Width / Screen.PrimaryScreen.WorkingArea.Width;
}
else
{
return pixels * SystemParameters.WorkArea.Height / Screen.PrimaryScreen.WorkingArea.Height;
}
}
public enum LengthDirection
{
Vertical, // |
Horizontal // ——
}
Run Code Online (Sandbox Code Playgroud)
这也适用于多个显示器.
归档时间: |
|
查看次数: |
39226 次 |
最近记录: |