最近在写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();
}
路过的大佬们如果有更好的方法,我在这里求教了,这个方法我也是被逼无奈才使用的,谢谢