C# 未正确显示符合条件的双精度图像

C# 未正确显示符合条件的双精度图像,c#,.net,properties,double,C#,.net,Properties,Double,我正在尝试使用限定的double设置一些控件的大小,这样无论控件显示在哪个屏幕上,控件大小都是相同的 所以我有一个转换器,它将double转换成合格的double: double effectiveValue = cm; string qualifiedDouble = effectiveValue + "cm"; LengthConverter lc = new LengthConverter(); double converted = (double)lc.ConvertFrom(quali

我正在尝试使用限定的double设置一些控件的大小,这样无论控件显示在哪个屏幕上,控件大小都是相同的

所以我有一个转换器,它将double转换成合格的double:

double effectiveValue = cm;
string qualifiedDouble = effectiveValue + "cm";
LengthConverter lc = new LengthConverter();
double converted = (double)lc.ConvertFrom(qualifiedDouble);
问题是,对于系统参数,例如分辨率或默认的系统缩放(idk英语如何称呼它)来说,它并不是真正有效的

您是否有任何线索,可以在任何分辨率、任何缩放设置等屏幕上显示以厘米为单位的完全相同的值

谢谢(大多数情况下)它应该可以工作,我做过几次类似的事情,但是你需要确保在你的桌面外观设置(以及图形卡设置、演示配置文件等-如果你有这样的软件)中,你禁用了所有缩放功能(设置为100%正常,没有大字体等)。我相信这就是你提到的“系统缩放”

将其设置为100%后,所有WPF单元应在任何屏幕上显示相同的内容。因此,所有屏幕上的10x10矩形(或10cmx10cm)看起来应该相同。如果使用qualified,那么在任何分辨率上都应该是相同的。在理论上,或者更确切地说,在操作系统的观点上

问题是,即使操作系统100%确信所有的计算都很好,仍然有一些卡/监视器配置可以向操作系统“撒谎”它们的功能。您无法从墙壁投影仪获得实际的DPI。一些具有wierd尺寸的显示器可以缩放图像,并会水平或垂直扭曲图像以填充整个屏幕,因此不会出现黑色边距。图形卡的软件驱动程序在内部也可以做到这一点,所以操作系统不会知道。WPF的DPI、设备独立单元和合格长度都是关于系统知道什么以及它们与真实屏幕的关系

但是,如果您确保禁用了所有系统缩放、屏幕填充、16:9/4:3翻译等功能,则大多数情况下都无法正确显示。你不能逃避让用户配置它。一旦他们这样做了,他们就可以用你的应用程序将显示的一些简单的“标尺”屏幕来验证结果。如果它仍然是错误的,那么这主要归咎于硬件,而你被卡住了。如果用户真的想让它运行,就需要更改它


顺便说一句,我没有找到任何方法来一致地处理“系统缩放”,这是操作系统显示中一个奇怪的部分。一开始似乎很简单,只需从注册表/etc读取设置并相应地放大/缩小,但后来发现,在不同的操作系统版本上(如winXP与win7),缩放的效果略有不同。。也许你会找到办法,我没有。我只是要求用户设置为100%。或者改变硬件,因为当他们已经将其设置为非100%时,它几乎总是表明他们的gpu/显示器具有奇怪的分辨率,并且有一些“智能软件”这做了一些额外的缩放。

因此我最终找到了一种方法,使用包含连接到计算机的显示器上的足够信息的。EDID存储在注册表中:

HKLM\SYSTEM\CurrentControlSet\Enum\\DISPLAY\ + displayId + registryId
下面是检索将cm转换为屏幕上像素的比率的代码

public static double GetCmToPixelRatio()
{
    var diagVector = GetActiveDisplayDiag();

    var width = System.Windows.SystemParameters.PrimaryScreenWidth;
    return width / diagVector.X;
}


public static int GetDPIX()
{
    var dpiXProperty = typeof(SystemParameters).GetProperty("DpiX", BindingFlags.NonPublic | BindingFlags.Static);

    return (int)dpiXProperty.GetValue(null, null);

}

private static Point GetActiveDisplayDiag()
{
    //get active display
    string wmiQuery = string.Format("Select * from Win32_DesktopMonitor");

    ManagementObjectSearcher searcher = new ManagementObjectSearcher(wmiQuery);
    ManagementObjectCollection retObjectCollection = searcher.Get();

    foreach (ManagementObject retObject in retObjectCollection)
    {
        try
        {
            //get display id
            string regPath = (string)retObject.GetPropertyValue("PNPDeviceID");
            if (regPath != null)
            {
                var pathInfo = regPath.Split('\\');
                var displayId = pathInfo[1];
                RegistryKey reg = Registry.LocalMachine.OpenSubKey("SYSTEM\\CurrentControlSet\\Enum\\DISPLAY\\" + displayId);
                var firstSubReg = reg.GetSubKeyNames()[0];
                reg = reg.OpenSubKey(firstSubReg + "\\Device Parameters");
                var edid = (byte[])reg.GetValue("EDID");
                return new Point(edid[21], edid[22]);
            }
        }
        catch (Exception) { }
    }
    return new Point();
}
我用它创建了我的转换器:

public class CmToPixelConverter : IValueConverter
{
    double ratio = DisplayHelper.GetCmToPixelRatio();

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (double)value * ratio;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

如果您想将GUI组件的大小调整为厘米(用放在显示器上的直尺测量),很遗憾,这是无法实现的。那么,在这种情况下,合格的double的目的是什么:Width=“20cm”@keithI guess WPF使用当前DPI(每英寸点数)将厘米转换为像素。主要问题是,电脑屏幕上的DPI不像打印机那样是一种物理测量。也许值得在谷歌上搜索DPI背后的计算机显示历史。谢谢你的回答Quetzalcatl,它部分回答了我的问题,但仍然有帮助。干杯!看起来很有趣!如果可以的话,我有一些问题-您是否对屏幕和应用程序的窗口进行了匹配?我的意思是,我在这里看到您使用“ActiveScreen”,但它如何与应用程序窗口所在的实际屏幕协调?我假设您使用第二个显示器作为“额外扩展的桌面空间”,所以我认为“活动”可能是两个屏幕中的一个,而窗口可能位于另一个屏幕上,从而影响计算?哦,您是否有任何问题,例如,将窗口拖动到第二个监视器时?也许这一切都没问题,我错了,但是代码看起来有点太简单了。我的应用程序托管在一台不允许多屏幕的计算机上,并且将一直全屏显示,这非常有帮助。但我仍然认为,您指出的事情可以通过使用Windows handle的pinvoke调用来处理