- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我的 WPF 应用程序在我的两台显示器笔记本电脑开发系统上表现出奇怪的行为。第二台显示器的分辨率为 1920 x 1080;笔记本电脑的分辨率为 1366 x 768。笔记本电脑运行的是 Windows 8.1,两个显示器的 DPI 设置都设置为 100%。插入后,第二台显示器是主显示器。显然,当第二台显示器没有插入时,笔记本电脑的显示器是主显示器。
应用程序窗口总是最大化,但可以最小化。无法拖动 问题与当您插入或拔出第二台显示器时窗口从一台显示器移动到另一台显示器时的显示方式有关。
当程序在插入第二台显示器的情况下启动时,它会在拔下电源时移动到笔记本电脑的显示器上。 WPF 代码也正确处理此更改。也就是说,它检测到原始尺寸无法适应新显示器,因此会重新绘制以适应新显示器。当第二个显示器重新插入时,它会移回第二个显示器并以该显示器的适当大小重新绘制自己。这正是我在这种情况下想要的。问题是当程序在其他配置中启动时。
当程序在没有插入第二台显示器的情况下启动时,它会以适合笔记本电脑显示器的尺寸绘制。在程序运行的情况下插入第二个显示器时,窗口移动到第二个显示器,但绘制错误。由于该程序已最大化,因此它的三边有一个巨大的黑色边框,内容显示在与笔记本电脑显示屏相同大小的区域中。
编辑:
我刚刚完成了一些测试,WPF 似乎无法正确处理从较小分辨率到较高分辨率的分辨率变化。该窗口的行为与我在笔记本电脑显示器上启动程序然后插入第二台显示器时得到的行为相同。至少是一致的。
我发现我可以通过处理 SystemEvents.DisplaySettingsChanged
获得有关何时插入第二台显示器或屏幕分辨率更改的通知。事件。在我的测试中,我发现当窗口从较小的显示器移动到较大的显示器时,Width
, Height
, ActualWidth
, 和 ActualHeight
当窗口移动到更大的窗口时不变。我能做的最好的事情就是获得 Height
& Width
属性值匹配监视器的工作区域,但 ActualWidth
和 ActualHeight
属性不会改变。
如何强制窗口将我的问题案例视为只是分辨率更改?或者,如何强制窗口更改其 ActualWidth
和 ActualHeight
属性为正确的值?
该窗口来自我编写的名为 DpiAwareWindow 的类:
public class DpiAwareWindow : Window {
private const int LOGPIXELSX = 88;
private const int LOGPIXELSY = 90;
private const int MONITOR_DEFAULTTONEAREST = 0x00000002;
protected enum MonitorDpiType {
MDT_Effective_DPI = 0,
MDT_Angular_DPI = 1,
MDT_Raw_DPI = 2,
MDT_Default = MDT_Effective_DPI
}
public Point CurrentDpi { get; private set; }
public bool IsPerMonitorEnabled;
public Point ScaleFactor { get; private set; }
protected HwndSource source;
protected Point systemDpi;
protected Point WpfDpi { get; set; }
public DpiAwareWindow()
: base() {
// Watch for SystemEvent notifications
SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged;
// Set up the SourceInitialized event handler
SourceInitialized += DpiAwareWindow_SourceInitialized;
}
~DpiAwareWindow() {
// Deregister our SystemEvents handler
SystemEvents.DisplaySettingsChanged -= SystemEvents_DisplaySettingsChanged;
}
private void DpiAwareWindow_SourceInitialized( object sender, EventArgs e ) {
source = (HwndSource) HwndSource.FromVisual( this );
source.AddHook( WindowProcedureHook );
// Determine if this application is Per Monitor DPI Aware.
IsPerMonitorEnabled = GetPerMonitorDPIAware() == ProcessDpiAwareness.Process_Per_Monitor_DPI_Aware;
// Is the window in per-monitor DPI mode?
if ( IsPerMonitorEnabled ) {
// It is. Calculate the DPI used by the System.
systemDpi = GetSystemDPI();
// Calculate the DPI used by WPF.
WpfDpi = new Point {
X = 96.0 * source.CompositionTarget.TransformToDevice.M11,
Y = 96.0 * source.CompositionTarget.TransformToDevice.M22
};
// Get the Current DPI of the monitor of the window.
CurrentDpi = GetDpiForHwnd( source.Handle );
// Calculate the scale factor used to modify window size, graphics and text.
ScaleFactor = new Point {
X = CurrentDpi.X / WpfDpi.X,
Y = CurrentDpi.Y / WpfDpi.Y
};
// Update Width and Height based on the on the current DPI of the monitor
Width = Width * ScaleFactor.X;
Height = Height * ScaleFactor.Y;
// Update graphics and text based on the current DPI of the monitor.
UpdateLayoutTransform( ScaleFactor );
}
}
protected Point GetDpiForHwnd( IntPtr hwnd ) {
IntPtr monitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST );
uint newDpiX = 96;
uint newDpiY = 96;
if ( GetDpiForMonitor( monitor, (int) MonitorDpiType.MDT_Effective_DPI, ref newDpiX, ref newDpiY ) != 0 ) {
return new Point {
X = 96.0,
Y = 96.0
};
}
return new Point {
X = (double) newDpiX,
Y = (double) newDpiY
};
}
public static ProcessDpiAwareness GetPerMonitorDPIAware() {
ProcessDpiAwareness awareness = ProcessDpiAwareness.Process_DPI_Unaware;
try {
Process curProcess = Process.GetCurrentProcess();
int result = GetProcessDpiAwareness( curProcess.Handle, ref awareness );
if ( result != 0 ) {
throw new Exception( "Unable to read process DPI level" );
}
} catch ( DllNotFoundException ) {
try {
// We're running on either Vista, Windows 7 or Windows 8. Return the correct ProcessDpiAwareness value.
awareness = IsProcessDpiAware() ? ProcessDpiAwareness.Process_System_DPI_Aware : ProcessDpiAwareness.Process_DPI_Unaware;
} catch ( EntryPointNotFoundException ) { }
} catch ( EntryPointNotFoundException ) {
try {
// We're running on either Vista, Windows 7 or Windows 8. Return the correct ProcessDpiAwareness value.
awareness = IsProcessDpiAware() ? ProcessDpiAwareness.Process_System_DPI_Aware : ProcessDpiAwareness.Process_DPI_Unaware;
} catch ( EntryPointNotFoundException ) { }
}
// Return the value in awareness.
return awareness;
}
public static Point GetSystemDPI() {
IntPtr hDC = GetDC( IntPtr.Zero );
int newDpiX = GetDeviceCaps( hDC, LOGPIXELSX );
int newDpiY = GetDeviceCaps( hDC, LOGPIXELSY );
ReleaseDC( IntPtr.Zero, hDC );
return new Point {
X = (double) newDpiX,
Y = (double) newDpiY
};
}
public void OnDPIChanged() {
ScaleFactor = new Point {
X = CurrentDpi.X / WpfDpi.X,
Y = CurrentDpi.Y / WpfDpi.Y
};
UpdateLayoutTransform( ScaleFactor );
}
public virtual void SystemEvents_DisplaySettingsChanged( object sender, EventArgs e ) {
// Get the handle for this window. Need to worry about a window that has been created by not yet displayed.
IntPtr handle = source == null ? new HwndSource( new HwndSourceParameters() ).Handle : source.Handle;
// Get the current DPI for the window we're on.
CurrentDpi = GetDpiForHwnd( handle );
// Adjust the scale factor.
ScaleFactor = new Point {
X = CurrentDpi.X / WpfDpi.X,
Y = CurrentDpi.Y / WpfDpi.Y
};
// Update the layout transform
UpdateLayoutTransform( ScaleFactor );
}
private void UpdateLayoutTransform( Point scaleFactor ) {
if ( IsPerMonitorEnabled ) {
if ( ScaleFactor.X != 1.0 || ScaleFactor.Y != 1.0 ) {
LayoutTransform = new ScaleTransform( scaleFactor.X, scaleFactor.Y );
} else {
LayoutTransform = null;
}
}
}
public virtual IntPtr WindowProcedureHook( IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled ) {
// Determine which Monitor is displaying the Window
IntPtr monitor = MonitorFromWindow( hwnd, MONITOR_DEFAULTTONEAREST );
// Switch on the message.
switch ( (WinMessages) msg ) {
case WinMessages.WM_DPICHANGED:
// Marshal the value in the lParam into a Rect.
RECT newDisplayRect = (RECT) Marshal.PtrToStructure( lParam, typeof( RECT ) );
// Set the Window's position & size.
Vector ul = source.CompositionTarget.TransformFromDevice.Transform( new Vector( newDisplayRect.left, newDisplayRect.top ) );
Vector hw = source.CompositionTarget.TransformFromDevice.Transform( new Vector( newDisplayRect.right = newDisplayRect.left, newDisplayRect.bottom - newDisplayRect.top ) );
Left = ul.X;
Top = ul.Y;
Width = hw.X;
Height = hw.Y;
// Remember the current DPI settings.
Point oldDpi = CurrentDpi;
// Get the new DPI settings from wParam
CurrentDpi = new Point {
X = (double) ( wParam.ToInt32() >> 16 ),
Y = (double) ( wParam.ToInt32() & 0x0000FFFF )
};
if ( oldDpi.X != CurrentDpi.X || oldDpi.Y != CurrentDpi.Y ) {
OnDPIChanged();
}
handled = true;
return IntPtr.Zero;
case WinMessages.WM_GETMINMAXINFO:
// lParam has a pointer to the MINMAXINFO structure. Marshal it into managed memory.
MINMAXINFO mmi = (MINMAXINFO) Marshal.PtrToStructure( lParam, typeof( MINMAXINFO ) );
if ( monitor != IntPtr.Zero ) {
MONITORINFO monitorInfo = new MONITORINFO();
GetMonitorInfo( monitor, monitorInfo );
// Get the Monitor's working area
RECT rcWorkArea = monitorInfo.rcWork;
RECT rcMonitorArea = monitorInfo.rcMonitor;
// Adjust the maximized size and position to fit the work area of the current monitor
mmi.ptMaxPosition.x = Math.Abs( rcWorkArea.left - rcMonitorArea.left );
mmi.ptMaxPosition.y = Math.Abs( rcWorkArea.top - rcMonitorArea.top );
mmi.ptMaxSize .x = Math.Abs( rcWorkArea.right - rcWorkArea.left );
mmi.ptMaxSize .y = Math.Abs( rcWorkArea.bottom - rcWorkArea.top );
}
// Copy our changes to the mmi object back to the original
Marshal.StructureToPtr( mmi, lParam, true );
handled = true;
return IntPtr.Zero;
default:
// Let the WPF code handle all other messages. Return 0.
return IntPtr.Zero;
}
}
[DllImport( "user32.dll", CallingConvention = CallingConvention.StdCall )]
protected static extern IntPtr GetDC( IntPtr hWnd );
[DllImport( "gdi32.dll", CallingConvention = CallingConvention.StdCall )]
protected static extern int GetDeviceCaps( IntPtr hDC, int nIndex );
[DllImport( "shcore.dll", CallingConvention = CallingConvention.StdCall )]
protected static extern int GetDpiForMonitor( IntPtr hMonitor, int dpiType, ref uint xDpi, ref uint yDpi );
[DllImport( "user32" )]
protected static extern bool GetMonitorInfo( IntPtr hMonitor, MONITORINFO lpmi );
[DllImport( "shcore.dll", CallingConvention = CallingConvention.StdCall )]
protected static extern int GetProcessDpiAwareness( IntPtr handle, ref ProcessDpiAwareness awareness );
[DllImport( "user32.dll", CallingConvention = CallingConvention.StdCall )]
protected static extern bool IsProcessDpiAware();
[DllImport( "user32.dll", CallingConvention = CallingConvention.StdCall )]
protected static extern IntPtr MonitorFromWindow( IntPtr hwnd, int flag );
[DllImport( "user32.dll", CallingConvention = CallingConvention.StdCall )]
protected static extern void ReleaseDC( IntPtr hWnd, IntPtr hDC );
}
public enum SizeMessages {
SIZE_RESTORED = 0,
SIZE_MINIMIZED = 1,
SIZE_MAXIMIZED = 2,
SIZE_MAXSHOW = 3,
SIZE_MAXHIDE = 4
}
public enum WinMessages : int {
WM_DPICHANGED = 0x02E0,
WM_GETMINMAXINFO = 0x0024,
WM_SIZE = 0x0005,
WM_WINDOWPOSCHANGING = 0x0046,
WM_WINDOWPOSCHANGED = 0x0047,
}
public enum ProcessDpiAwareness {
Process_DPI_Unaware = 0,
Process_System_DPI_Aware = 1,
Process_Per_Monitor_DPI_Aware = 2
}
Window
类(class)。我需要找到一种方法来解决这个问题。但是,我可能是错的。
DpiAwareWindow
下降的普通窗口。类(class)。当屏幕分辨率改变时,它表现出类似的行为。但是,作为测试,我更改了代码,因此窗口是从 Window 类派生的,我没有看到行为。所以在
DpiAwareWindow
中有一些东西不起作用的代码。
WinMessages.WM_GETMINMAXINFO
注释掉,问题就不会发生。
WindowProcedureHook
中的案例方法的
switch
陈述。此代码的目的是限制最大化窗口的大小,使其不会遮挡任务栏。
最佳答案
我终于解决了这个问题。事实证明,我需要做的是更改 switch
中的一行。 WindowProcedureHook
中的声明方法:
case WinMessages.WM_GETMINMAXINFO:
// lParam has a pointer to the MINMAXINFO structure. Marshal it into managed memory.
MINMAXINFO mmi = (MINMAXINFO) Marshal.PtrToStructure( lParam, typeof( MINMAXINFO ) );
if ( monitor != IntPtr.Zero ) {
MONITORINFO monitorInfo = new MONITORINFO();
GetMonitorInfo( monitor, monitorInfo );
// Get the Monitor's working area
RECT rcWorkArea = monitorInfo.rcWork;
RECT rcMonitorArea = monitorInfo.rcMonitor;
// Adjust the maximized size and position to fit the work area of the current monitor
mmi.ptMaxPosition.x = Math.Abs( rcWorkArea.left - rcMonitorArea.left );
mmi.ptMaxPosition.y = Math.Abs( rcWorkArea.top - rcMonitorArea.top );
mmi.ptMaxSize .x = Math.Abs( rcWorkArea.right - rcWorkArea.left );
mmi.ptMaxSize .y = Math.Abs( rcWorkArea.bottom - rcWorkArea.top );
}
// Copy our changes to the mmi object back to the original
Marshal.StructureToPtr( mmi, lParam, true );
handled = false; // This line used to set handled to true
return IntPtr.Zero;
WM_GETMINMAXINFO
收到的消息仍然运行,但它使用对
MINMAXINFO
的更改代码创建的对象以完成其工作。通过此更改,WPF 窗口可以正确处理分辨率更改。
SystemEvent.DisplaySettingsChanged
不再需要事件处理程序。
关于c# - 移动到更大的显示器时,窗口无法正确调整大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22103947/
https://github.com/mattdiamond/Recorderjs/blob/master/recorder.js中的代码 我不明白 JavaScript 语法,比如 (functio
在 iOS 7 及更早版本中,如果我们想在应用程序中找到 topMostWindow,我们通常使用以下代码行 [[[UIApplication sharedApplication] windows]
我已经尝试解决这个问题很长一段时间了:我无法访问窗口的 url,因为它位于另一个域上..有一些解决方案吗? function login() { var cb = window.ope
是否可以将 FFMPEG 视频流传递到 C# 窗口?现在它在新窗口中作为新进程打开,我只是想将它传递给我自己的 SessionWindow。 此时我像这样执行ffplay: public void E
我有一个名为 x 的矩阵看起来像这样: pTime Close 1 1275087600 1.2268 2 1275264000 1.2264 3 1275264300 1.2
在编译时,发生搜索,grep搜索等,Emacs会在单独的窗口中创建一个新的缓冲区来显示结果,有没有自动跳转到那个窗口的方法?这很有用,因为我可以使用 n 和 p 而不是 M-g n 和 M-g p 移
我有一个启动 PowerShell 脚本的批处理文件。 批处理文件: START Powershell -executionpolicy RemoteSigned -noexit -file "MyS
我有一个基于菜单栏的应用程序,单击图标时会显示一个窗口。在 Mac OS X Lion 上一切正常,但由于某种原因,在 Snow Leopard 和早期版本的 Mac OS X 上会出现错误。任何时候
在 macOS 中,如何在 Xcode 和/或 Interface Builder 中创建带有“集成标题栏和工具栏”的窗口? 这是“宽标题栏”类型的窗口,已添加到 OS X 10.10 Yosemit
在浏览器 (Chrome) 中 JavaScript: var DataModler = { Data: { Something: 'value' }, Process: functi
我有 3 个 html 页面。第 1 页链接到第 2 页,第 2 页链接到第 3 页(为了简单起见)。 我希望页面 2 中的链接打开页面 3 并关闭页面 1(选项卡 1)。 据我了解,您无法使用 Ja
当点击“创建节点”按钮时,如何打开一个新的框架或窗口?我希望新框架包含一个文本字段和下拉菜单,以便用户可以选择一个选项。 Create node Search node
我有一个用户控件,用于编辑应用程序中的某些对象。 我最近遇到一个实例,我想弹出一个新的对话框(窗口)来托管此用户控件。 如何实例化新窗口并将需要设置的任何属性从窗口传递到用户控件? 感谢您的宝贵时间。
我有一个Observable,它发出许多对象,我想使用window或buffer操作对这些对象进行分组。但是,我不想指定count参数来确定窗口中应包含多少个对象,而是希望能够使用自定义条件。 例如,
我有以下代码,它打开一个新的 JavaFX 阶段(我们称之为窗口)。 openAlertBox.setOnAction(e -> { AlertBox alert = AlertBox
我要添加一个“在新窗口中打开”上下文菜单项,该菜单项将以新的UIScene打开我的应用程序文档之一。当然,我只想在实际上支持多个场景的设备上显示该菜单项。 目前,我只是在检查设备是否是使用旧设备的iP
我正在尝试创建一个 AIR 应用程序来记录应用程序的使用情况,使用 AIR 从系统获取信息的唯一简单方法是使用命令行工具和抓取 标准输出 . 我知道像 这样的工具顶部 和 ps 对于 OS X,但它们
所以我有这个简单的 turtle 螺旋制作器,我想知道是否有一种方法可以打印出由该程序创建的我的设计副本。 代码: import turtle x= float(input("Angle: ")) y
我正在编写一个 C# WPF 程序,它将文本消息发送到另一个程序的窗口。我有一个宏程序作为我的键盘驱动程序 (Logitech g15) 的一部分,它已经这样做了,尽管它不会将击键直接发送到进程,而是
我尝试使用以下代码通过 UDP 发送,但得到了奇怪的结果。 if((sendto(newSocket, sendBuf, totalLength, 0, (SOCKADDR *)&sendAd
我是一名优秀的程序员,十分优秀!