• wpf单位转换及DPI获取


    wpf使用设备无关单位,一开始的理解是无论DPI怎么变,显示的窗口大小是一样的,实际效果窗口会随着系统DPI缩放(哪里错了?请大佬明示);wpf设备无关单位转换成物理单位是与DPI无关的,下面给出一个Dpi结构:

    public struct Dpi {
        public Dpi (Double x, Double y) {
            DpiX = x;
            DpiY = y;
    
            Px2WpfX = 96 / DpiX;
            Px2WpfY = 96 / DpiY;
        }
    
        public Double DpiX { get; }
    
        public Double DpiY { get; }
    
        public Double Px2WpfX { get; }
    
        public Double Px2WpfY { get; }
    
        /// <summary>
        /// 英寸-厘米
        /// </summary>
        public static readonly Double In2Cm = 2.54;
        /// <summary>
        /// 英寸-磅
        /// </summary>
        public static readonly Double In2Pt = 72;
        /// <summary>
        /// 厘米-wpf
        /// </summary>
        public static readonly Double Cm2Wpf = 96 / 2.54;
    }

    可以看到,wpf设备无关单位转厘米的比例是固定的,继而又可以转换成英寸、磅等,只有换算成像素才需要DPI;下面说一下如何获取DPI。

    .net core提供了VisualTreeHelper.GetDpi(Visual visual)方法,返回DpiScale结构,PixelsPerInchX表示1英寸像素数(即DPI),DpiScaleX表示1个wpf设备无关单位可以转换成多少像素;并且Window、Image等对象还提供了DpiChanged事件,非常方便根据DPI变化调整大小;

    .net framework 4.8以下没有上述便利得方法;获取dpi的方法参考https://blog.csdn.net/Iron_Ye/article/details/83053393,里面说了多种获取DPI的方法,并且向我们推荐使用CompositionTarget方式,经测试(本人Win10),改变系统显示比例150%后,除Win32API外,其他方法获取的DPI与显示比列为100%无异,而Win32API获取的DPI与.net core使用VisualTreeHelper.GetDpi()一样,所以得出结论,若要获取准确的DPI,推荐使用Win32API,每次传入窗口句柄或Intptr.Zero,我的猜想是这样的(没有去验证,我只有一块屏幕),传入窗口句柄则获取窗口句柄所在屏幕的DPI,传入Intptr.Zero则相当于传入空指针,即获取主屏幕DPI;另外CompositionTarget需要注意一下,PresentationSource.FromVisual(visual)传入DrawingVisual会返回null,需要传入DrawingVisual所在的逻辑树结构对象(一般是Canvas);与Dpi结构配合,这里给出DpiHelper类示范:

    public sealed class DpiHelper {
        #region Graphics
    
        public static Dpi GetDpiByGraphics (IntPtr hWnd) {
            using (var graphics = Graphics.FromHwnd (hWnd)) {
                return new Dpi (graphics.DpiX, graphics.DpiY);
            }
        }
    
        #endregion
    
        #region CompositionTarget
    
        public static Dpi GetDpiFromVisual (Visual visual) {
            var source = PresentationSource.FromVisual (visual);
            return (source == null || source.CompositionTarget == null) ? GetDpiByWin32 (IntPtr.Zero) : new Dpi (96.0 * source.CompositionTarget.TransformToDevice.M11, 96.0 * source.CompositionTarget.TransformToDevice.M22);
        }
    
        #endregion
    
        #region Win32 API
    
        private const Int32 LOGPIXELSX = 88;
        private const Int32 LOGPIXELSY = 90;
    
        [DllImport ("gdi32.dll")]
        private static extern Int32 GetDeviceCaps (IntPtr hdc, Int32 index);
    
        [DllImport ("user32.dll")]
        private static extern IntPtr GetDC (IntPtr hWnd);
    
        [DllImport ("user32.dll")]
        private static extern Int32 ReleaseDC (IntPtr hWnd, IntPtr hDc);
    
        public static Dpi GetDpiByWin32 (IntPtr hwnd) {
            var hDc = GetDC (hwnd);
    
            var dpiX = GetDeviceCaps (hDc, LOGPIXELSX);
            var dpiY = GetDeviceCaps (hDc, LOGPIXELSY);
    
            ReleaseDC (hwnd, hDc);
            return new Dpi (dpiX, dpiY);
        }
    
        #endregion
    }
  • 相关阅读:
    Mac上安装Git
    原型对象和原型链
    ES6入门
    一边宽度固定,一边宽度自适应
    15种css居中方式
    阿里CDN核心技术解密
    尽量用const,enum,inline代替define
    Nginx安装
    百度笔试题:malloc/free与new/delete的区别(转)
    C++内存管理(转)
  • 原文地址:https://www.cnblogs.com/pumbaa/p/13728833.html
Copyright © 2020-2023  润新知