如何将 WPF 英寸单位转换为 Winforms 像素单位,反之亦然?

2023-11-24

我有一扇设计在WPF我在一个中心使用了它WinForms所有者。 现在,我想移动所有者表单,目前我的WPF窗口也必须移动到窗体的中心!

但我有一个问题,只有当窗口位于屏幕中心窗体的中心时。否则以与 Windows 坐标不同的形式进行操作。 我只是将窗体的位移值添加到窗口位置。

现在我得出的结论是,WPF Windows 上的像素坐标与 WinForms 不同!

如何转换WPF窗口位置到WinForms基地位置,反之亦然?

业主表格代码是:

public partial class Form1 : Form
{
    private WPF_Window.WPF win;

    public Form1()
    {
        InitializeComponent();

        win = new WPF();
        win.Show();
        CenterToParent(win);
    }

    private void CenterToParent(System.Windows.Window win)
    {
        win.Left = this.Left + (this.Width - win.Width) / 2;
        win.Top = this.Top + (this.Height - win.Height) / 2;
    }

    protected override void OnMove(EventArgs e)
    {
        base.OnMove(e);
        CenterToParent(win);
    }
}

在WPF中获取DPI值的最佳方法

Method 1

这与在 Windows 窗体中执行此操作的方式相同。System.Drawing.Graphics对象提供了方便的属性来获取水平和垂直 DPI。让我们画出一个辅助方法:

/// <summary>
/// Transforms device independent units (1/96 of an inch)
/// to pixels
/// </summary>
/// <param name="unitX">a device independent unit value X</param>
/// <param name="unitY">a device independent unit value Y</param>
/// <param name="pixelX">returns the X value in pixels</param>
/// <param name="pixelY">returns the Y value in pixels</param>
public void TransformToPixels(double unitX,
                              double unitY,
                              out int pixelX,
                              out int pixelY)
{
    using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
    {
        pixelX = (int)((g.DpiX / 96) * unitX);
        pixelY = (int)((g.DpiY / 96) * unitY);
    }

    // alternative:
    // using (Graphics g = Graphics.FromHdc(IntPtr.Zero)) { }
}

您可以使用它来转换坐标和大小值。它非常简单、健壮,并且完全采用托管代码(至少对于您(消费者)而言)。通过IntPtr.Zero as HWND or HDC参数结果为Graphics包装整个屏幕的设备上下文的对象。

但这种方法有一个问题。它依赖于 Windows Forms/GDI+ 基础结构。您必须添加对 System.Drawing 程序集的引用。有什么大不了的?不确定你的情况,但对我来说这是一个需要避免的问题。


Method 2

让我们更深入地了解一下,以 Win API 的方式来实现。GetDeviceCaps函数检索指定设备的各种信息,并且当我们传递它时能够检索水平和垂直 DPILOGPIXELSX and LOGPIXELSY分别参数。

GetDeviceCaps函数定义在gdi32.dll可能是什么System.Drawing.Graphics在引擎盖下使用。

让我们看看我们的助手变成了什么样子:

[DllImport("gdi32.dll")]
public static extern int GetDeviceCaps(IntPtr hDc, int nIndex);

[DllImport("user32.dll")]
public static extern IntPtr GetDC(IntPtr hWnd);

[DllImport("user32.dll")]
public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDc);

public const int LOGPIXELSX = 88;
public const int LOGPIXELSY = 90;

/// <summary>
/// Transforms device independent units (1/96 of an inch)
/// to pixels
/// </summary>
/// <param name="unitX">a device independent unit value X</param>
/// <param name="unitY">a device independent unit value Y</param>
/// <param name="pixelX">returns the X value in pixels</param>
/// <param name="pixelY">returns the Y value in pixels</param>
public void TransformToPixels(double unitX,
                              double unitY,
                              out int pixelX,
                              out int pixelY)
{
    IntPtr hDc = GetDC(IntPtr.Zero);
    if (hDc != IntPtr.Zero)
    {
        int dpiX = GetDeviceCaps(hDc, LOGPIXELSX);
        int dpiY = GetDeviceCaps(hDc, LOGPIXELSY);

        ReleaseDC(IntPtr.Zero, hDc);

        pixelX = (int)(((double)dpiX / 96) * unitX);
        pixelY = (int)(((double)dpiY / 96) * unitY);
    }
    else
        throw new ArgumentNullException("Failed to get DC.");
}

因此,我们将对托管 GDI+ 的依赖关系替换为对精美 Win API 调用的依赖关系。这是一种改进吗?在我看来是的,只要我们在 Windows 上运行 Win API 就是最小公分母。它很轻。在其他平台上,我们可能一开始就不会遇到这种困境。

不要被这个愚弄了ArgumentNullException。该解决方案与第一个解决方案一样强大。System.Drawing.Graphics如果它也无法获取设备上下文,则会抛出相同的异常。


Method 3

正如官方记录的那样here注册表中有一个特殊的键:HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontDPI.它存储一个 DWORD 值,该值正是用户在显示设置对话框中为 DPI 选择的值(在那里称为字体大小)。

阅读它是理所当然的,但我不推荐它。您会看到官方 API 和各种设置的存储之间存在差异。 API 是一个公共合约,即使内部逻辑被完全重写,它也保持不变(如果不是整个平台很糟糕,不是吗?)。

但没有人保证内部存储会保持不变。它可能已经持续了几十年,但描述其搬迁的重要设计文件可能已经等待批准。你永远不会知道。

始终坚持使用 API(无论是什么,本机、Windows 窗体、WPF 等)。即使底层代码从您知道的位置读取值。


Method 4

这是一种非常优雅的 WPF 方法,我发现它记录在这篇博文。它基于提供的功能System.Windows.Media.CompositionTarget最终表示绘制 WPF 应用程序的显示表面的类。该类提供了 2 个有用的方法:

  • TransformFromDevice
  • TransformToDevice

这些名称是不言自明的,在这两种情况下我们都会得到一个System.Windows.Media.Matrix包含设备单元(像素)和独立单元之间的映射系数的对象。 M11 将包含 X 轴系数,M22 - Y 轴系数。

到目前为止,我们一直在考虑单位->像素方向,让我们用以下代码重写我们的助手CompositionTarget.TransformToDevice.调用此方法时,M11 和 M22 将包含我们计算得出的值:

  • 分辨率/96
  • 分辨率/96

因此,在 DPI 设置为 120 的机器上,系数将为 1.25。

这是新的助手:

/// <summary>
/// Transforms device independent units (1/96 of an inch)
/// to pixels
/// </summary>
/// <param name="visual">a visual object</param>
/// <param name="unitX">a device independent unit value X</param>
/// <param name="unitY">a device independent unit value Y</param>
/// <param name="pixelX">returns the X value in pixels</param>
/// <param name="pixelY">returns the Y value in pixels</param>
public void TransformToPixels(Visual visual,
                              double unitX,
                              double unitY,
                              out int pixelX,
                              out int pixelY)
{
    Matrix matrix;
    var source = PresentationSource.FromVisual(visual);
    if (source != null)
    {
        matrix = source.CompositionTarget.TransformToDevice;
    }
    else
    {
        using (var src = new HwndSource(new HwndSourceParameters()))
        {
            matrix = src.CompositionTarget.TransformToDevice;
        }
    }

    pixelX = (int)(matrix.M11 * unitX);
    pixelY = (int)(matrix.M22 * unitY);
}

我必须向该方法添加一个参数,即Visual。我们需要它作为计算的基础(之前的示例使用整个屏幕的设备上下文)。我认为这不是一个大问题,因为您很可能会遇到Visual运行 WPF 应用程序时即可使用(否则,为什么需要转换像素坐标?)。但是,如果您的视觉对象尚未附加到演示文稿源(即尚未显示),您将无法获取演示文稿源(因此,我们检查 NULL 并构造一个新的HwndSource).

参考

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何将 WPF 英寸单位转换为 Winforms 像素单位,反之亦然? 的相关文章

  • 如何使用 Regsvr32 注册 .NET COM DLL?

    我有一个使用 COM DLL 的 VB6 应用程序 该DLL是用C 编写的 在 C 项目属性中 我检查了 Register for COM interop 选项 VB6 应用程序在我的开发机器上运行良好 C 代码完全遵循以下格式 CodeP
  • 类型定义存在于两个库中

    我正在使用 NET 4 5 构建 ASP NET Web 窗体网站 错误 The type System ComponentModel DataAnnotations Schema ForeignKeyAttribute exists in
  • C# 中 value 为匿名类型的字典

    是否可以在 C 中创建一个System Collections Generic Dictionary
  • flowlayoutpanel和水平滚动条问题

    我正在使用一个 flowlayoutpanel 它有很多逻辑上的按钮 我遇到的问题是 当我调整窗口大小时 当窗口变小时 我无法看到所有水平排列的按钮 相反 当窗口变小时 按钮会下降到下一行 谁能帮我解决这个问题 我只是希望按钮水平排列 当窗
  • WPF 中可选择的 TextBlock 或带有格式化文本的 TextBox

    我遇到一种情况 我需要显示格式化文本 正常 粗体 突出显示 并且还应该是可选择的 以便用户可以复制文本 我使用了文本块 我可以使用内联内容流元素应用多种格式 但不幸的是它的文本不可选择 虽然文本框允许选择文本并复制到剪贴板 但它不允许我设置
  • System.NotSupportedException:“集合是只读的。”从 iList 中删除对象时抛出

    运行下面的代码片段时抛出异常 我有一个 iListof webelements 如果该元素包含字符串 WSC 我想将其从 iList 中删除 谁能帮我吗 代码如下 IList
  • 从动态服务器中抓取 html 列表数据

    哈喽大家好 抱歉提出转储问题 这是我最后的手段 我发誓我尝试了无数其他 Stackoverflow 问题 不同的框架等 但这些似乎没有帮助 我有以下问题 一个网站显示一个数据列表 前面有大量的 div li span 等标签 它是一个很大的
  • 需要帮助将 winform 迁移到 net 5

    我正在将 winform 应用程序从 net core 3 1 移植到 net 5 并收到以下错误 严重性代码 说明 项目文件行抑制状态 错误NETSDK1136 目标平台必须设置为Windows 通常 通过在 TargetFramewor
  • 变形:Opencv 使用 Visual Studio 将图像显示到曲面屏幕

    我正在尝试使用 opencv API 来扭曲图像 以便将其显示到曲面屏幕上 我已经浏览了opencv中提供的翘曲apihere http docs opencv org 2 4 modules stitching doc warpers h
  • 给出对象的指针作为参数

    假设我有 void func foo obj 我有 foo object 我该如何制作object进入争论func 只需取消引用它即可 func object
  • OpenCV:处理每一帧

    我想使用 OpenCV 编写一个跨平台应用程序进行视频捕获 在所有示例中 我发现来自相机的帧是使用抓取功能进行处理并等待一段时间 我想处理序列中的每一帧 我想定义自己的回调函数 每次当一个新帧准备好处理时都会执行该函数 例如直播对于 Win
  • Parallel ForEach 的本地初始化如何工作?

    我不确定 Parallel ForEach 中本地 init 函数的使用 如 msdn 文章中所述 http msdn microsoft com en us library dd997393 aspx http msdn microsof
  • ASP.NET Core中间件如何进行DI?

    我正在尝试将依赖项注入到我的中间件构造函数中 如下所示 public class CreateCompanyMiddleware private readonly RequestDelegate next private readonly
  • 允许使用 AutoMapper 或类似工具映射动态类型吗?

    我已经开始使用https github com robconery massive https github com robconery massive对于一个项目 我想知道是否有任何映射工具可以支持动态到静态类型的映射 我以前使用过 Au
  • 实例着色器矩阵的设置

    我想绘制实例立方体 我可以打电话GL DrawArraysInstanced PrimitiveType Triangles 0 36 2 成功地 我的问题是所有立方体都绘制在相同的位置和相同的旋转 我如何为每个立方体单独更改它 要创建不同
  • 底部垂直滚动richtextbox [WPF]

    我有一个富文本框 当满了时我想自动滚动到底部 这可能吗 用xaml做这个吗 通过使用ScrollViewer ScrollChanged http msdn microsoft com en us library system window
  • 隐式类型转换 - 编译器错误

    这个问题与this https stackoverflow com questions 3529449 can i make the ternary operator treat my class like a bool问题 下面的代码在V
  • 所有区域的启用保护模式必须设置为相同的值(启用或禁用)

    我正在尝试使用Selenium Internet Explorer驱动程序 但当我尝试实例化它时它崩溃了 TestInitialize public void TestInitialise ieDriver new InternetExpl
  • 将整个单词与特殊字符匹配的正则表达式不起作用? [复制]

    这个问题在这里已经有答案了 我正在经历这个问题C Regex Match 整个单词 https stackoverflow com q 1209049 443568 它说要匹配整个单词使用 b模式 b 这对于匹配没有任何特殊字符的整个单词效
  • wpf中的图像问题(图像不显示)

    我不明白为什么我无法在 WPF 中显示图像 也许我不小心修改了我的资源文件夹 这就是我没有显示的原因 所以我创建了一个新的 wpf 应用程序 我有这个 当我运行该程序时 我的图片显示为 为什么当我尝试在程序中执行相同的操作时 图像没有显示

随机推荐

  • C++ 先前的定义错误

    因此 感谢这个网站 我找到了之前问题的答案 我正在向 GNU automake 项目中的类添加一个函数 该函数使用指向doc目的 依赖项包含在 Makefile am 文件中以包含doc h and plsa h按各自的顺序 但是 当我编译
  • 为什么这段代码不抛出 NullPointerException

    我只是和我的朋友讨论使用类名调用静态方法 并尝试了这段代码 并期望它在运行时抛出 NPE 但事实证明它没有作用 我只是想了解执行顺序 public class One public static void method System out
  • NSObject.BroadSystemFontWeights 警告消息是什么意思?

    我最近将 XCode 更新到 7 0 并收到以下警告消息 Xcode IDEInterfaceBuilder Cocoa NSObject BroadSystemFontWeights 这是什么意思以及如何摆脱它 当我将字体粗细设置为时 我
  • 使用 document.execCommand('copy') 复制到剪贴板因大文本而失败

    我使用隐藏文本区域来放置一些文本 选择它 然后使用 document execCommand 将其复制到剪贴板 这通常有效 但当文本很大时会失败 返回 false 在 Chrome v55 中 它似乎在 180K 字符左右失败 通过这种方式
  • 如何使用 Haskell 向量编写并行代码?

    一只手 在 Haskell 中Vector a似乎是用作数字数组的首选类型 甚至还有一个 不完整的 矢量教程 另一方面 Control Parallel Strategies主要是根据Traversable 矢量库不提供这些实例 的最小完整
  • 如何批量更新 postgres 中的单个列 5500 万条记录

    我想更新 postgres 表的一列 记录大约有 5500 万条 因此我们需要批量更新 10000 条记录 注意 我们要更新所有行 但我们不想锁定我们的桌子 我正在尝试以下查询 Update account set name Some na
  • git 子模块 foreach 不工作

    我想弄清楚为什么git submodule foreach命令对我不起作用 我克隆了一个 git 存储库 它有几个子模块 我想立即初始化并更新所有子模块以获取子模块源 但无论我尝试 git submodule foreach 都不适合我 我
  • 如何在地址栏上显示标志?

    我想在地址栏上显示徽标 但它仅在标题旁边的选项卡上可见 简短的回答 是的 这就是许多浏览器的工作原理 火狐浏览器 http msujaws wordpress com 2012 04 23 an update to site identit
  • 为什么实现接口的类中的通用成员函数不能采用类(而不是接口)类型的参数?

    考虑一个接口IDog用方法likes
  • 通过多列进行 SQL 过滤

    我有一个 MySql 表 我想查询其中的行pairs列位于特定集合中 例如 假设我的表如下所示 id f1 f2 1 a 20 2 b 20 3 a 30 4 b 20 5 c 20 现在 我希望提取其中该对的行 f1 f2 是 a 30
  • 在 R 中:通过对范围内的值进行布尔比较来索引向量:index==c(min : max)

    在 R 中 假设我们有一个向量 area c rep c 26 30 5 rep c 500 504 5 rep c 550 554 5 rep c 76 80 5 和另一个向量yield c 1 100 现在 假设我想像这样建立索引 gt
  • 如何在 Selenium 中等待警报框执行操作?

    我按下取消按钮 根据我的代码 它正在检查一些文本 在 Chrome 和 Firefox 中 它工作正常 但在 IE 中 在警报框上执行操作需要时间 但代码会移动到下一行 所以我想要一些代码停止 直到在警报框中执行操作 然后才进入下一步 我正
  • Mercurial CGI (hgweb.cgi) 失败

    我在虚拟机上运行的 Win 2k8 R2 上安装了 Mercurial 1 8 1 Python 2 6 6 我尝试过从 msi 源代码和使用 tortisehg 安装 命令行 Hg 工作正常 但运行 hgweb cgi 时出现相同的错误
  • 加载 YOLO:标量变量的索引无效

    收到 IndexError 错误 yolo layers 行上标量变量的索引无效 network cv2 dnn readNetFromDarknet yolov3 cfg yolov3 weights layers network get
  • 在 C 中安全地将 char* 双关

    在开源中方案一 写道 我正在从文件中读取二进制数据 由另一个程序写入 并输出整数 双精度数 以及其他各种数据类型 挑战之一是它需要 在两种字节序的 32 位和 64 位机器上运行 这意味着我 最终不得不做相当多的低级操作 我认识一个 非常
  • 将图像水平居中定位并使高度为视口的 100%

    我有一张图像占据了视口的整个高度 图像高度应跨越整个视口高度 100 以便适合查看的屏幕 此处已完成 并且宽度应与高度成相对比例 正如您在我的页面中看到的 http lamininbeauty co za 页面两侧有空间 我希望图像水平居中
  • Spring Batch - 计算已处理的行数

    因此 我正在创建一个 Spring Batch 作业来读取 CSV 文件以及包含不完整数据的某些行 它检查该行不完整 并将其输出到日志 然后跳过 它工作得很好 除了在工作结束时我希望它记录它发现的不完整的行数 只是一些简单的事情 比如 发现
  • 在数据库中查找最接近的数值

    我需要找到一个 select 语句 该语句将返回与我的输入完全匹配的记录 或者如果未找到完全匹配则返回最接近的匹配 这是到目前为止我的选择声明 SELECT FROM myTable WHERE Name Test AND Size 2 A
  • 网上有什么好的 UIScrollView 教程吗? [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 目前不接受答案 任何好的链接都将受到高度赞赏 这将转到社区维基 一些很好的示例 涵盖了基本功能 非常简单的 uiscrollview 演示 滚动 UiScrollV
  • 如何将 WPF 英寸单位转换为 Winforms 像素单位,反之亦然?

    我有一扇设计在WPF我在一个中心使用了它WinForms所有者 现在 我想移动所有者表单 目前我的WPF窗口也必须移动到窗体的中心 但我有一个问题 只有当窗口位于屏幕中心窗体的中心时 否则以与 Windows 坐标不同的形式进行操作 我只是