Hoe krijg ik de DPI in WPF?

Hoe kan ik de DPI in WPF krijgen?


Antwoord 1, autoriteit 100%

https:// docs.microsoft.com/en-us/archive/blogs/jaimer/getting-system-dpi-in-wpf-applijkt te werken

PresentationSource source = PresentationSource.FromVisual(this);
double dpiX, dpiY;
if (source != null) {
    dpiX = 96.0 * source.CompositionTarget.TransformToDevice.M11;
    dpiY = 96.0 * source.CompositionTarget.TransformToDevice.M22;
}

Antwoord 2, autoriteit 64%

var dpiXProperty = typeof(SystemParameters).GetProperty("DpiX", BindingFlags.NonPublic | BindingFlags.Static);
var dpiYProperty = typeof(SystemParameters).GetProperty("Dpi", BindingFlags.NonPublic | BindingFlags.Static);
var dpiX = (int)dpiXProperty.GetValue(null, null);
var dpiY = (int)dpiYProperty.GetValue(null, null);

Antwoord 3, autoriteit 46%

Met .NET 4.6.2 Preview en hoger kunt u VisualTreeHelper.GetDpi(Visual visual). Het retourneert een DpiScalestructuur, die u de DPI vertelt waarop het gegeven Visualzal worden of is weergegeven.


Antwoord 4, autoriteit 9%

De enige manier die ik heb gevonden om de “echte” monitor-dpi te krijgen, is de volgende. Alle andere genoemde technieken zeggen gewoon 96, wat niet correct is voor de meeste monitoren.

public class ScreenInformations
{
    public static uint RawDpi { get; private set; }
    static ScreenInformations()
    {
        uint dpiX;
        uint dpiY;
        GetDpi(DpiType.RAW, out dpiX, out dpiY);
        RawDpi = dpiX;
    }
    /// <summary>
    /// Returns the scaling of the given screen.
    /// </summary>
    /// <param name="dpiType">The type of dpi that should be given back..</param>
    /// <param name="dpiX">Gives the horizontal scaling back (in dpi).</param>
    /// <param name="dpiY">Gives the vertical scaling back (in dpi).</param>
    private static void GetDpi(DpiType dpiType, out uint dpiX, out uint dpiY)
    {
        var point = new System.Drawing.Point(1, 1);
        var hmonitor = MonitorFromPoint(point, _MONITOR_DEFAULTTONEAREST);
        switch (GetDpiForMonitor(hmonitor, dpiType, out dpiX, out dpiY).ToInt32())
        {
            case _S_OK: return;
            case _E_INVALIDARG:
                throw new ArgumentException("Unknown error. See https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510.aspx for more information.");
            default:
                throw new COMException("Unknown error. See https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510.aspx for more information.");
        }
    }
    //https://msdn.microsoft.com/en-us/library/windows/desktop/dd145062.aspx
    [DllImport("User32.dll")]
    private static extern IntPtr MonitorFromPoint([In]System.Drawing.Point pt, [In]uint dwFlags);
    //https://msdn.microsoft.com/en-us/library/windows/desktop/dn280510.aspx
    [DllImport("Shcore.dll")]
    private static extern IntPtr GetDpiForMonitor([In]IntPtr hmonitor, [In]DpiType dpiType, [Out]out uint dpiX, [Out]out uint dpiY);
    const int _S_OK = 0;
    const int _MONITOR_DEFAULTTONEAREST = 2;
    const int _E_INVALIDARG = -2147024809;
}
/// <summary>
/// Represents the different types of scaling.
/// </summary>
/// <seealso cref="https://msdn.microsoft.com/en-us/library/windows/desktop/dn280511.aspx"/>
public enum DpiType
{
    EFFECTIVE = 0,
    ANGULAR = 1,
    RAW = 2,
}

Antwoord 5, autoriteit 9%

Ik heb mijn antwoord van 2015 bijgewerkt. Hier is een hulpprogrammacode die de nieuwste DPI-functies van Windows 10 gebruikt (met name GetDpiForWindow-functiewat de enige methode is die de DPI_AWARENESS van het venster/toepassing/proces, enz. ondersteunt, maar terugvalt op oudere ( dpi per monitor en desktop dpi), dus het zou nog steeds moeten werken met Windows 7.

Het is niet afhankelijk van WPF of Winforms, alleen van Windows zelf.

// note this class considers dpix = dpiy
public static class DpiUtilities
{
    // you should always use this one and it will fallback if necessary
    // https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getdpiforwindow
    public static int GetDpiForWindow(IntPtr hwnd)
    {
        var h = LoadLibrary("user32.dll");
        var ptr = GetProcAddress(h, "GetDpiForWindow"); // Windows 10 1607
        if (ptr == IntPtr.Zero)
            return GetDpiForNearestMonitor(hwnd);
        return Marshal.GetDelegateForFunctionPointer<GetDpiForWindowFn>(ptr)(hwnd);
    }
    public static int GetDpiForNearestMonitor(IntPtr hwnd) => GetDpiForMonitor(GetNearestMonitorFromWindow(hwnd));
    public static int GetDpiForNearestMonitor(int x, int y) => GetDpiForMonitor(GetNearestMonitorFromPoint(x, y));
    public static int GetDpiForMonitor(IntPtr monitor, MonitorDpiType type = MonitorDpiType.Effective)
    {
        var h = LoadLibrary("shcore.dll");
        var ptr = GetProcAddress(h, "GetDpiForMonitor"); // Windows 8.1
        if (ptr == IntPtr.Zero)
            return GetDpiForDesktop();
        int hr = Marshal.GetDelegateForFunctionPointer<GetDpiForMonitorFn>(ptr)(monitor, type, out int x, out int y);
        if (hr < 0)
            return GetDpiForDesktop();
        return x;
    }
    public static int GetDpiForDesktop()
    {
        int hr = D2D1CreateFactory(D2D1_FACTORY_TYPE.D2D1_FACTORY_TYPE_SINGLE_THREADED, typeof(ID2D1Factory).GUID, IntPtr.Zero, out ID2D1Factory factory);
        if (hr < 0)
            return 96; // we really hit the ground, don't know what to do next!
        factory.GetDesktopDpi(out float x, out float y); // Windows 7
        Marshal.ReleaseComObject(factory);
        return (int)x;
    }
    public static IntPtr GetDesktopMonitor() => GetNearestMonitorFromWindow(GetDesktopWindow());
    public static IntPtr GetShellMonitor() => GetNearestMonitorFromWindow(GetShellWindow());
    public static IntPtr GetNearestMonitorFromWindow(IntPtr hwnd) => MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);
    public static IntPtr GetNearestMonitorFromPoint(int x, int y) => MonitorFromPoint(new POINT { x = x, y = y }, MONITOR_DEFAULTTONEAREST);
    private delegate int GetDpiForWindowFn(IntPtr hwnd);
    private delegate int GetDpiForMonitorFn(IntPtr hmonitor, MonitorDpiType dpiType, out int dpiX, out int dpiY);
    private const int MONITOR_DEFAULTTONEAREST = 2;
    [DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr LoadLibrary(string lpLibFileName);
    [DllImport("kernel32", CharSet = CharSet.Ansi, SetLastError = true)]
    private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName);
    [DllImport("user32")]
    private static extern IntPtr MonitorFromPoint(POINT pt, int flags);
    [DllImport("user32")]
    private static extern IntPtr MonitorFromWindow(IntPtr hwnd, int flags);
    [DllImport("user32")]
    private static extern IntPtr GetDesktopWindow();
    [DllImport("user32")]
    private static extern IntPtr GetShellWindow();
    [StructLayout(LayoutKind.Sequential)]
    private partial struct POINT
    {
        public int x;
        public int y;
    }
    [DllImport("d2d1")]
    private static extern int D2D1CreateFactory(D2D1_FACTORY_TYPE factoryType, [MarshalAs(UnmanagedType.LPStruct)] Guid riid, IntPtr pFactoryOptions, out ID2D1Factory ppIFactory);
    private enum D2D1_FACTORY_TYPE
    {
        D2D1_FACTORY_TYPE_SINGLE_THREADED = 0,
        D2D1_FACTORY_TYPE_MULTI_THREADED = 1,
    }
    [InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("06152247-6f50-465a-9245-118bfd3b6007")]
    private interface ID2D1Factory
    {
        int ReloadSystemMetrics();
        [PreserveSig]
        void GetDesktopDpi(out float dpiX, out float dpiY);
        // the rest is not implemented as we don't need it
    }
}
public enum MonitorDpiType
{
    Effective = 0,
    Angular = 1,
    Raw = 2,
}

Antwoord 6, autoriteit 5%

Zo ben ik erin geslaagd om een ​​”schaalfactor” in WPF te krijgen.
De resolutie van mijn laptop is 1920×1440.

int resHeight = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;  // 1440
int actualHeight = SystemParameters.PrimaryScreenHeight;  // 960
double ratio = actualHeight / resHeight;
double dpi = resHeigh / actualHeight;  // 1.5 which is true because my settings says my scale is 150%

Antwoord 7, autoriteit 4%

Gebruik GetDeviceCapsfunctie:

   static void Main(string[] args)
    {
        // 1.25 = 125%
        var dpi = GetDpi();
    }
    [DllImport("user32.dll")]
    public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
    [DllImport("user32.dll")]
    public static extern IntPtr GetDC(IntPtr hwnd);
    [DllImport("gdi32.dll")]
    static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
    private static float GetDpi()
    {
        IntPtr desktopWnd = IntPtr.Zero;
        IntPtr dc = GetDC(desktopWnd);
        var dpi = 100f;
        const int LOGPIXELSX = 88;
        try
        {
            dpi = GetDeviceCaps(dc, LOGPIXELSX);
        }
        finally
        {
            ReleaseDC(desktopWnd, dc);
        }
        return dpi / 96f;
    }

Antwoord 8

U kunt proberen om ManagementClass te gebruiken:

public static string GetDPI()
        {
            using (ManagementClass mc = new ManagementClass("Win32_DesktopMonitor"))
            {
                using (ManagementObjectCollection moc = mc.GetInstances())
                {
                    int PixelsPerXLogicalInch = 0; // dpi for x
                    int PixelsPerYLogicalInch = 0; // dpi for y
                    foreach (ManagementObject each in moc)
                    {
                        PixelsPerXLogicalInch = int.Parse((each.Properties["PixelsPerXLogicalInch"].Value.ToString()));
                        PixelsPerYLogicalInch = int.Parse((each.Properties["PixelsPerYLogicalInch"].Value.ToString()));
                    }
                    return PixelsPerXLogicalInch + "," + PixelsPerYLogicalInch;
                }
            }
        }

Antwoord 9

Er zijn
https:/ /blogs.windows.com/buildingapps/2017/01/25/calling-windows-10-apis-desktop-application/#FJtMAIFjbtXiLQAp.97

25 januari 2017 15:54

‘Windows 10 API’s aanroepen vanuit een desktoptoepassing’
en

https://docs.microsoft.com /en-us/uwp/api/windows.devices.display.displaymonitor

“Display​Monitor-klasse”

Naamruimte: Windows.Devices.Display Assemblies:Windows.Devices.Display.dll, Windows.dll

Biedt informatie over een beeldscherm dat op het systeem is aangesloten.

Deze gegevens omvatten veelgebruikte informatie uit de Extended Display Identification Data van de monitor (EDID, een industriestandaard weergavedescriptorblok dat door bijna alle monitoren wordt gebruikt om beschrijvingen van ondersteunde modi en algemene apparaatinformatie te geven) en DisplayID (wat een nieuwere industriestandaard die een superset van EDID biedt).

Raw​DpiX
Haalt de fysieke horizontale DPI van de monitor op (gebaseerd op de oorspronkelijke resolutie en fysieke grootte van de monitor).

Raw​DpiY
Krijgt de fysieke verticale DPI van de monitor (op basis van de native resolutie en fysieke grootte van de monitor).

Other episodes