【问题标题】:Window.Left is wrong when moving a maximized Window with Windows + Shift + Arrow Keys使用 Windows + Shift + 箭头键移动最大化的窗口时,Window.Left 是错误的
【发布时间】:2019-11-18 14:00:58
【问题描述】:

我在 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 或 Google 上没有找到任何关于此的内容。 非常感谢您提供解决方法、提示或解决方案。

【问题讨论】:

  • 我不确定我是否理解 Windows + Shift + Cursor Left/Right 快捷方式,您的意思是 Windows + Shift + Left/Right arrow 吗?使用此快捷方式时,我也无法重现该问题。也许您的Application.Current.MainWindow 未设置为正确的Window?
  • 是的,我的意思是方向键,我的错。这是正确的窗口,如果我用鼠标拖放它会按预期更改左侧。
  • 您能否创建一个新的空 WPF 应用程序并将您的 MainWindow 的默认构造函数替换为以下调试代码:public MainWindow() { InitializeComponent(); async Task Test() { while (true) { Console.WriteLine((Left, Top)); await Task.Delay(500); } }; Test(); }。它在输出窗口中显示Window 的当前位置,即使使用快捷方式也对我有用。它不适合你吗?
  • 我用你的测试场景重现了这个错误,这个问题只有在 WindowState 被最大化时才会出现。
  • 尝试使用 _actualLeft 和 _actualTop 字段。这种特殊情况的代码可以在here找到。

标签: c# wpf


【解决方案1】:

尝试使用这个:

    WindowInteropHelper windowInteropHelper = new WindowInteropHelper(Application.Current.MainWindow);
    Screen screen = System.Windows.Forms.Screen.FromHandle(windowInteropHelper.Handle);

Screen Bounds 属性提供整个窗口的坐标,WorkingArea 提供没有标题栏和停靠窗口的区域的边界。

【讨论】:

  • 我选择了你的答案,因为它比@Corentin Pane 的答案产生的开销更少,我已经在引用 System.Window.Forms 并且只需要检查一次位置而不跟踪窗口或任何东西.现在,如果Application.Current.MainWindow 处于最大化状态,我只检查屏幕边界,否则我使用 MainWindow 本身。现在像魅力一样工作。感谢你们俩的帮助。
  • @kirbby 是的,我没有意识到不需要跟踪:)
  • 我没有在帖子中明确提及,如果您需要跟踪,您的回答会更好,这就是为什么我也赞成您的回答,谢谢:)
【解决方案2】:

您应该使用win32 API 来检索您想要的信息,因为 .NET 公开的事件不足以检测到这种情况。

你必须做两件事:

  1. 收听与窗口移动相对应的WndProc 消息(完整列表here)。我们想要的是WM_MOVE,等于0x0003。详情请见this thread。
  2. 即使Window处于Maximized状态,也能够确定它的真实位置,我们可以使用GetWindowRect方法来做到这一点。详情请见this thread。

这将是在移动时打印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;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-27
    相关资源
    最近更新 更多