zoukankan      html  css  js  c++  java
  • 关于WPF 禁止 DPI缩放的一种解决办法

    最近在写wpf的时候发现一个问题,原本定义的580*180 的窗口 在Show的时候窗口被放大了,后来发现是电脑显示器 放大了 125%

     放在平时 倒也无伤大雅,可是我现在写的窗口 需要按照自己的方式来定位,窗口被放大后 再按照自己的坐标来定位位置 窗口就跑飞了,

    百度了各种方法之后 无果,只能手动写了,思路是这样的,先获取电脑屏幕放大了多少,然后 show之前 除以放大的倍数,就是之前设定的长宽

    首先获取 DPI放大的倍数 网上查的代码如下(原文链接https://www.freesion.com/article/8117154244/)

    WINFORM:

    1)通过窗体或者控件的句柄来获得(推荐使用)

    首先引入using System.Drawing.dll ;

    代码如下:

    Graphics currentGraphics = Graphics.FromHwnd(form.Handle);
    double dpixRatio = currentGraphics.DpiX/96;
    double dpiyRatio = currentGraphics.DpiY/96;

    (2)通过Graphics来获取

    首先引入using System.Drawing.dll ;

    代码如下:

    using (Graphics graphics = Graphics.FromHwnd(IntPtr.Zero))
    {
        float dpiX = graphics.DpiX;
        float dpiY = graphics.DpiY;
    }

    3)用ManagementClass来获取

    首先引入using System.Management.dll;

    代码如下:

    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()));
            }
        }
    }

    WPF:

    1)WPF窗体获取dpi

    WindowInteropHelper winHelper = new WindowInteropHelper((MainWindow)App.Current.MainWindow);
    IntPtr mainWindowHandle = winHelper.Handle;
    Graphics currentGraphics = Graphics.FromHwnd(mainWindowHandle);
    double currentDpiX = currentGraphics.DpiX;
    double currentDpiY = currentGraphics.DpiY;
    double dpiXRatio = currentDpiX / 96;   
    double dpiYRatio = currentDpiY / 96;   

    注:这种方法必须有App.xaml的存在才可以使用。

    2)WPF控件获取dpi

    <1>通过当前WPF控件对象获取

    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;
    }
    double dpixRatio = dpiX/96;
    double dpiyRatio = dpiY/96;

    注:由于使用了PresentationSource.FromVisual,所以必须在加载完控件之后才能使用。即最好放在Control的Loaded事件中使用。

    <2>通过WPF的空间的句柄获得

    IntPtr hwnd = ((HwndSource)PresentationSource.FromVisual(wpfControl)).Handle
    Graphics currentGraphics = Graphics.FromHwnd(hwnd);
    double dpixRatio = currentGraphics.DpiX/96;
    double dpiyRatio = currentGraphics.DpiY/96;

    注:同<1>中的注意要点。

    <3>无任何的前提的方法(来自StackFlow)(推荐使用)

    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);
    var dpixRatio = dpiX/96;
    var dpiyRatio = dpiY/96;

    关于WPF中使用WINDOWSFORMSHOST承载WINFORM控件时大小的问题

    在承载时,要在Winform控件中使用如下的代码进行调整:

    代码如下:

    this.AutoScaleMode = AutoScaleMode.Inherit;
    this.BackgroundImageLayout = ImageLayout.Stretch;

    注:如果不使用,那么Host中的空间会出现变形的问题。而且放大的大小比放大之后来的更加的大。

    (2)WINFORM中通过获取屏幕大小来限制窗体的全屏显示

    代码如下:

    System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width
    System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height

    (3)WPF中通过获取屏幕大小来限制窗体的全屏显示

    代码如下:

    SystemParameters.WorkArea.Size.Width
    SystemParameters.WorkArea.Size.Height

    注:返回当前屏幕工作区的宽和高(除去任务栏)

    (3)WPF中可以使用绑定和转换器来处理

    转换器代码如下(转载自博客园水手《WPF 屏蔽DPI改变对程序的影响的解决方案》):

    DPIConverter类

    [ValueConversion(typeof(object), typeof(object))]
    public class DPIConverter : IvalueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            WindowInteropHelper winHelper = new             WindowInteropHelper((MainWindow)App.Current.MainWindow);
            IntPtr mainWindowHandle = winHelper.Handle;
            Graphics currentGraphics = Graphics.FromHwnd(mainWindowHandle);
            double currentDpiX = currentGraphics.DpiX;
            double dpiXRatio = currentDpiX / 96;   
            if (targetType == typeof(GridLength))
            {
                double data = double.Parse(parameter.ToString());
                GridLength gridLength = new GridLength(data / dpiXRatio,             GridUnitType.Pixel);
                return gridLength;
            }
            if (targetType == typeof(Thickness))
            {
                Thickness margin = (Thickness)parameter;
                if (margin != null)
                {
                    margin.Top = margin.Top / dpiXRatio;
                    margin.Left = margin.Left / dpiXRatio;
                    margin.Right = margin.Right / dpiXRatio;
                    margin.Bottom = margin.Bottom / dpiXRatio;
                    return margin;
                }
            }
            if (targetType == typeof(double))
            {
                double fontSize = double.Parse(parameter.ToString());
                return fontSize / dpiXRatio;
            }
     
            if(targetType==typeof(System.Windows.Point))
            {
                System.Windows.Point point=(System.Windows.Point)parameter;
                point.X=point.X/dpiXRatio;
                point.Y=point.Y/dpiXRatio;
                return point;
            }
            return null;
        }
     
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return null;
        }
    }
    <Image Name="imageIcon" Stretch="Fill" HorizontalAlignment="Left" VerticalAlignment="Top" Width="{Binding Converter={StaticResource DPIConverter},ConverterParameter=32}" Height="{Binding Converter={StaticResource DPIConverter},ConverterParameter=32}">
        <Image.Margin>
            <Binding Converter="{StaticResource DPIConverter}">
                <Binding.ConverterParameter>
                    <Thickness Left="18" Top="24" Right="0" Bottom="48"/>
                </Binding.ConverterParameter>
            </Binding>
        </Image.Margin>    
    </Image>
     

    以上就是获取DPI的方法(放大的倍数)

    上面的方法中我使用的是 通过控件来获取DPI 然后我定义了一个窗口的基类 新写了个 ShowNewDialog 的函数 如下

    首先在程序loaded之后获取DPI 并记录到一个静态变量里

    private void LoginMmView_Loaded(object sender, RoutedEventArgs e)
            {
                PresentationSource source = PresentationSource.FromVisual(this);
                double dpiX = 0, dpiY = 0;
                if (source != null)
                {
                    dpiX = 96.0 * source.CompositionTarget.TransformToDevice.M11;
                    dpiY = 96.0 * source.CompositionTarget.TransformToDevice.M22;
                }
                PamirNmsModule.DPIxRatio = dpiX / 96;
                PamirNmsModule.DPIyRatio = dpiY / 96;
            }

    窗口基类里的ShowNewDialog

    public  bool? ShowNewDialog(ContentControl parent = null)
            {
                this.Width = this.Width / PamirNmsModule.DPIxRatio;
                this.Height = this.Height / PamirNmsModule.DPIyRatio;
                if (parent == null)
                {
                    var mainWindow = ControlHelper.GetTopWindow();
                    if (mainWindow != null)
                    {
                        this.Owner = mainWindow;
                    }
    
                }
                else
                {
                    Point p = parent.TranslatePoint(new Point(), Application.Current.MainWindow);
    
                    double hw = (parent.ActualWidth / PamirNmsModule.DPIxRatio - this.Width) / 2 + (p.X);
                    double hh = (parent.ActualHeight / PamirNmsModule.DPIyRatio - this.Height) / 2 + (p.Y);
                    this.Left = hw;
                    this.Top = hh;
                }
    
                return this.ShowDialog();
            }

    路过的大佬们如果有更好的方法,我在这里求教了,这个方法我也是被逼无奈才使用的,谢谢

    不想平凡,奈何太懒 T_T
  • 相关阅读:
    servlet.txt笔记
    用数组实现集合的功能
    用父类声明的变量和用接口声明的变量的区别
    DHTML_____document对象的方法
    DHTML_____window对象的事件
    DHTML_____window对象属性
    DHTML_____window对象方法
    DHTML_____如何编写事件处理程序
    常用点击事件(鼠标、光标、键盘、body)
    鼠标滑动显示不同页面的效果——————获取鼠标相对于整个页面的坐标
  • 原文地址:https://www.cnblogs.com/wuyaxiansheng/p/15351643.html
Copyright © 2011-2022 走看看