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

 

路過的大佬們如果有更好的方法,我在這里求教了,這個方法我也是被逼無奈才使用的,謝謝


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM