关于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
原文地址:https://www.cnblogs.com/wuyaxiansheng/p/15351643.html