我在WPF(C#(中遇到了一个问题,我需要在父窗口中的某个点上放置一个弹出窗口。我用Application.Current.MainWindow.Left
和Application.Current.MainWindow.Top
获得父位置,只要我不使用Windows快捷键Windows+Shift+将窗口从一个监视器移动到另一个监视器,它就可以工作◄/►。如果我使用快捷方式,属性将与移动窗口前保持不变。
窗口必须是WindowState.Maximized
,如果没有最大化,它就可以工作。
我也试过用Window.GetWindow(this)
代替Application.Current.MainWindow
,结果是一样的。
似乎Application.Current.MainWindow
没有发生positionchanged事件,也没有更新Left
和Top
属性。
我在SO或谷歌上没有找到任何关于这方面的信息。非常感谢提供变通方法、提示或解决方案。
尝试使用这个:
WindowInteropHelper windowInteropHelper = new WindowInteropHelper(Application.Current.MainWindow);
Screen screen = System.Windows.Forms.Screen.FromHandle(windowInteropHelper.Handle);
Screen Bounds属性提供了整个窗口的坐标,WorkingArea提供了没有标题栏和停靠窗口的区域的边界。
您应该使用win32
API来检索您想要的信息,因为.NET公开的事件不足以检测这种情况。
你必须做两件事:
- 收听与窗口移动相对应的
WndProc
消息(此处为完整列表(。我们想要的是WM_MOVE
,并且等于0x0003
。有关详细信息,请参阅此线程 - 即使处于
Maximized
状态,也能够确定Window
的真实位置,这可以通过使用GetWindowRect
方法来实现。有关详细信息,请参阅此线程
这是组装好的代码,当Window
被移动时,它会打印它的左上角位置,包括使用您描述的快捷方式。
public partial class MainWindow : Window {
HwndSource source;
const short WM_MOVE = 0x0003;
public MainWindow() {
InitializeComponent();
// Loaded event needed to make sure the window handle has been created.
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e) {
// Subscribe to win32 level events
source = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
source.AddHook(new HwndSourceHook(WndProc));
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
if (msg == WM_MOVE) {
Console.WriteLine("Window has moved!");
GetWindowRect(new HandleRef(this, new WindowInteropHelper(this).Handle), out RECT rect);
Console.WriteLine("New location is " + (rect.Left, rect.Top));
}
return IntPtr.Zero;
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetWindowRect(HandleRef hWnd, out RECT lpRect);
[StructLayout(LayoutKind.Sequential)]
public struct RECT {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
}