最近在寫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();
}
路過的大佬們如果有更好的方法,我在這里求教了,這個方法我也是被逼無奈才使用的,謝謝