在鼠标位置(鼠标左上角)显示 WPF 窗口的最佳方式是啥?

Posted

技术标签:

【中文标题】在鼠标位置(鼠标左上角)显示 WPF 窗口的最佳方式是啥?【英文标题】:What is the best way to show a WPF window at the mouse location (to the top left of the mouse)?在鼠标位置(鼠标左上角)显示 WPF 窗口的最佳方式是什么? 【发布时间】:2013-11-15 03:27:43 【问题描述】:

我发现通过继承 Windows 窗体鼠标点并减去窗口的高度和宽度来设置左侧和顶部(因为我的窗口的大小是固定的),这部分时间是有效的:

MyWindowObjectThatInheritsWindow window = new MyWindowObjectThatInheritsWindow();
System.Windows.Point mouseLocation = GetMousePositionWindowsForms();
window.Left = mouseLocation.X - 300;
window.Top = mouseLocation.Y - 240;
window.Show();

编辑:这是获取鼠标位置的代码...

public System.Windows.Point GetMousePositionWindowsForms()

    System.Drawing.Point point = System.Windows.Forms.Control.MousePosition;
    return new System.Windows.Point(point.X, point.Y);

请注意,这是通过使窗口的右下边缘接触鼠标光标的左上角来实现的。但这会因不同的屏幕分辨率或多台具有不同分辨率的显示器而中断?我还没有完全缩小范围,但我只是在另一台 PC 上尝试了相同的代码,它似乎生成的窗口不是鼠标光标的左上角,而是它的左下角,而且距离很远过去了……

我可能应该将我的窗口大小添加到内容、宽度和高度,所以我不能只使用 ActualWidth 和 ActualHeight 属性,因为它们不可用。也许问题在于正确调整大小?有没有办法做到这一点?根据我的主 PC 和运行 1920x1080 分辨率的两台显示器,我确定 300 和 240 是正确的,因为我已经计算了我明确调整大小的窗口中所有对象的宽度和高度。编辑:刚刚尝试将高度和宽度显式设置为 240/300,以确保窗口不再按内容调整大小,并且在减去实际高度和宽度时我仍然遇到这个问题!

有什么想法吗?

【问题讨论】:

不清楚您到底想要什么,甚至不清楚您的代码做了什么(究竟是什么返回 GetMousePositionWindowsForms?)。你能说清楚一点吗? 没问题。简而言之:我想将 WPF 窗口的右下边缘设置为鼠标光标的左上角。你要求的功能我已经加进去了。 问题或多或少很清楚;但您的代码并不过分:它似乎是 C# winforms 和 WPF 的混合体。无论如何,我想你可以和你得到的回答者继续这个讨论。 @varocarbas 是的,它使用 WinForms 来获取屏幕上的鼠标点,但不幸的是,我得到的答案似乎不适用于我的情况,因为我的 MainWindow 是隐藏的,因为我的应用程序只包含一个系统托盘图标。 我不熟悉这种混合(通常,你可以直接在 WPF 中获得任何你想要的东西,或者创建一个 winforms 应用程序)。这可能不会引发问题(错误地协调两个不同的框架)?在任何情况下,只需向 Sheridan 解释确切的条件,以便他能够提出适合您的解决方案。 【参考方案1】:

最后,这成功了:

        protected override void OnContentRendered(EventArgs e)
        
            base.OnContentRendered(e);
            MoveBottomRightEdgeOfWindowToMousePosition();
        

        private void MoveBottomRightEdgeOfWindowToMousePosition()
        
            var transform = PresentationSource.FromVisual(this).CompositionTarget.TransformFromDevice;
            var mouse = transform.Transform(GetMousePosition());
            Left = mouse.X - ActualWidth;
            Top = mouse.Y - ActualHeight;
        

        public System.Windows.Point GetMousePosition()
        
            System.Drawing.Point point = System.Windows.Forms.Control.MousePosition;
            return new System.Windows.Point(point.X, point.Y);
        

【讨论】:

效果很好。将事情连接到“加载”事件时,我的运气会更好;如果我使用 OnContentRendered,我发现当对话框从其初始渲染位置移动时会出现闪烁效果【参考方案2】:

你不能用这样的东西吗?:

Point mousePositionInApp = Mouse.GetPosition(Application.Current.MainWindow);
Point mousePositionInScreenCoordinates = 
    Application.Current.MainWindow.PointToScreen(mousePositionInApp);

我无法对其进行测试,但我认为它应该可以工作。


更新>>>

您不必在这些方法中使用Application.Current.MainWindow 作为参数...如果您可以访问Button 或另一个UIElement,它应该仍然有效处理程序:

Point mousePositionInApp = Mouse.GetPosition(openButton);
Point mousePositionInScreenCoordinates = openButton.PointToScreen(mousePositionInApp);

同样,我无法对此进行测试,但如果也失败了,那么您可以在 How do I get the current mouse screen coordinates in WPF? 帖子中找到另一种方法。

【讨论】:

我已经尝试过了,但我从中得到了这个错误:PresentationCore.dll 中发生了“System.InvalidOperationException”类型的未处理异常附加信息:此 Visual 未连接到 PresentationSource。 啊,对不起。在MainWindow.xaml.cs 的构造函数中,尝试添加:Application.Current.MainWindow = this;。如果这仍然不起作用,请尝试推迟对上述代码的调用...有关更多信息,请参阅this post。 啊,实际上这行不通,因为我的 MainWindow 是隐藏的。我制作了一个 WPF 应用程序,它创建了一个任务栏图标并立即创建了一个隐藏窗口,所以我仍然看到这个错误。实际上,上面的代码来自 MainWindow.cs,所以我只是尝试使用“this”对象,但不幸的是没有运气。这是 MainWindow XAML: schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="schemas.microsoft.com/winfx/2006/xaml" Visibility="Hidden"/> 我不确定我是否理解...那么Window 用于您的应用程序吗? 好问题。我不用窗户。我在系统托盘中创建了一个系统托盘图标。当用户单击它时,事件处理程序会触发并为应用程序的用户界面创建一个窗口(实际上不是 MainWindow)。【参考方案3】:

您也可以通过稍微修改初始示例并在显示窗口之前定位窗口来做到这一点。

MyWindowObjectThatInheritsWindow window = new MyWindowObjectThatInheritsWindow();

var helper = new WindowInteropHelper(window);
var hwndSource = HwndSource.FromHwnd(helper.EnsureHandle());
var transformFromDevice = hwndSource.CompositionTarget.TransformFromDevice;

System.Windows.Point wpfMouseLocation = transformFromDevice.Transform(GetMousePositionWindowsForms());
window.Left = wpfMouseLocation.X - 300;
window.Top = wpfMouseLocation.Y - 240;
window.Show();

【讨论】:

以上是关于在鼠标位置(鼠标左上角)显示 WPF 窗口的最佳方式是啥?的主要内容,如果未能解决你的问题,请参考以下文章

WPF 程序鼠标在窗口之外的时候,控件拿到的鼠标位置在哪里?

WPF里,怎么通过鼠标移动的位置来控制滚动条

为啥 WPF 中的鼠标位置不正确,而缩放桌面上的 Winforms 则不正确?

WPF 获取鼠标屏幕位置窗口位置控件位置

qt窗口左下角在鼠标位置弹出

为啥鼠标不能超过电脑屏幕的左,上边界,而能够超过