[C# VSTO Word]Form窗体在不同电脑上相同宽度值不同显示效果的情况处理。暨如何正确获取Windows11/10桌面的缩放比例?
发现问题
发现UserControl任务窗格,在new之后设定好的宽度,在不同的word版本展示的实际宽度不对等。
- 一台电脑上,启动的word版本【16.0.15128.20178】宽度377
- 另一台电脑上,启动的word版本【16.0.14430.20298】宽度376
- 目测很明显,实际宽度相差非常大。
经过几轮代码测试和环境筛查,终于发现造成这种情况不是因为word版本的问题,而是因为操作系统的缩放比例不是100%造成的。
- 因此将系统的缩放比例设置成100%。
- 不同缩放比例下,控件的相同的宽度显示效果并不一样 甚至有的控件被阉割了:
- 缩放比例100%模式下,UserControl任务窗格情况与之前一模一样了。
测试准备
-
通过代码获取Windows的缩放比例。发现网上的都不对,指的都是未使用物理分辨率的缩放。而非系统的【缩放】。通过来自CSDN【kkbinkbi】博客的代码测试。最终确定为DPI的比例
• 缩放100%=DPI:96
• 缩放125%=DPI:120
• 缩放150%=DPI:144 -
摘录来自CSDN【kkbinkbi】博客的类代码如下。并将namespace调整为自己的目录结构。
using System;
using System.Drawing;
using System.Runtime.InteropServices;
namespace WordAddIn_will段落处理.APIClass
{
public class PrimaryScreen
{
#region Win32 API
[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr ptr);
[DllImport("gdi32.dll")]
static extern int GetDeviceCaps(
IntPtr hdc, // handle to DC
int nIndex // index of capability
);
[DllImport("user32.dll", EntryPoint = "ReleaseDC")]
static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDc);
#endregion
#region DeviceCaps常量
const int HORZRES = 8;
const int VERTRES = 10;
const int LOGPIXELSX = 88;
const int LOGPIXELSY = 90;
const int DESKTOPVERTRES = 117;
const int DESKTOPHORZRES = 118;
#endregion
#region 属性
/// <summary>
/// 获取屏幕分辨率当前物理大小
/// </summary>
public static Size WorkingArea
{
get {
IntPtr hdc = GetDC(IntPtr.Zero);
Size size = new Size();
size.Width = GetDeviceCaps(hdc, HORZRES);
size.Height = GetDeviceCaps(hdc, VERTRES);
ReleaseDC(IntPtr.Zero, hdc);
return size;
}
}
/// <summary>
/// 当前系统DPI_X 大小 一般为96
/// </summary>
public static int DpiX
{
get
{
IntPtr hdc = GetDC(IntPtr.Zero);
int DpiX = GetDeviceCaps(hdc, LOGPIXELSX );
ReleaseDC(IntPtr.Zero, hdc);
return DpiX;
}
}
/// <summary>
/// 当前系统DPI_Y 大小 一般为96
/// </summary>
public static int DpiY
{
get
{
IntPtr hdc = GetDC(IntPtr.Zero);
int DpiX = GetDeviceCaps(hdc,LOGPIXELSY);
ReleaseDC(IntPtr.Zero, hdc);
return DpiX;
}
}
/// <summary>
/// 获取真实设置的桌面分辨率大小
/// </summary>
public static Size DESKTOP
{
get
{
IntPtr hdc = GetDC(IntPtr.Zero);
Size size = new Size();
size.Width = GetDeviceCaps(hdc,DESKTOPHORZRES );
size.Height = GetDeviceCaps(hdc, DESKTOPVERTRES);
ReleaseDC(IntPtr.Zero, hdc);
return size;
}
}
/// <summary>
/// 获取宽度缩放百分比
/// </summary>
public static float ScaleX
{
get
{
IntPtr hdc = GetDC(IntPtr.Zero);
int t = GetDeviceCaps(hdc, DESKTOPHORZRES);
int d = GetDeviceCaps(hdc, HORZRES);
float ScaleX = (float)GetDeviceCaps(hdc, DESKTOPHORZRES) / (float)GetDeviceCaps(hdc, HORZRES);
ReleaseDC(IntPtr.Zero, hdc);
return ScaleX;
}
}
/// <summary>
/// 获取高度缩放百分比
/// </summary>
public static float ScaleY
{
get
{
IntPtr hdc = GetDC(IntPtr.Zero);
float ScaleY = (float)(float)GetDeviceCaps(hdc, DESKTOPVERTRES) / (float)GetDeviceCaps(hdc, VERTRES);
ReleaseDC(IntPtr.Zero, hdc);
return ScaleY;
}
}
#endregion
}
}
- 在自己的【will测试文中对象】UserControl任务窗格代码中加入识别,然后输出(输出到控件中的代码略)
#region 获取Windows操作系统的显示参数,以确定缩放比例指向
string string_获取Windows操作系统的显示 = "";
string_获取Windows操作系统的显示 += (string.Format("获取高度缩放百分比【{0}】" + Environment.NewLine, APIClass.PrimaryScreen.ScaleY.ToString()));
string_获取Windows操作系统的显示 += (string.Format("获取宽度缩放百分比【{0}】" + Environment.NewLine, APIClass.PrimaryScreen.ScaleX.ToString()));
string_获取Windows操作系统的显示 += (string.Format("获取真实设置的桌面分辨率大小【{0}】" + Environment.NewLine, APIClass.PrimaryScreen.DESKTOP.ToString()));
string_获取Windows操作系统的显示 += (string.Format("获取屏幕分辨率当前物理大小【{0}】" + Environment.NewLine, APIClass.PrimaryScreen.WorkingArea.ToString()));
string_获取Windows操作系统的显示 += (string.Format("当前系统DPI_Y 大小 一般为96【{0}】" + Environment.NewLine, APIClass.PrimaryScreen.DpiY.ToString()));
string_获取Windows操作系统的显示 += (string.Format("当前系统DPI_X 大小 一般为96【{0}】" + Environment.NewLine, APIClass.PrimaryScreen.DpiX.ToString()));
#endregion
测试结果
- 测试缩放比例125%时:
- 其中DPI为120;
- 任务窗格UserControl的显示效果如下图。
- 测试缩放比例150%时:
- 其中DPI为144;
- 任务窗格UserControl的显示效果如下图。
- 测试缩放比例为100%时:
- 其中DPI为96;
- 任务窗格UserControl的显示效果如下图。
经验总结
○ 控件中with和height等属性的显示效果,受系统缩放比例,即DPI影响。
○ 在控件实例化的时候,需要识别DPI,然后根据其调整控件的大小。
○ 在Visual studio 中调试控件样式时,一定要测试不同系统桌面缩放比例,即DPI。
问题解决
- 将UserControl任务窗格的【AutoScaleMode】属性设置成【Inherit】
- 经调整Windows11、Windows10的显示【缩放】比例,发现问题解决。
美图分享