AvalonDock(Dirkster版本):在ILayoutUpdateStrategy中设置浮动LayoutDocument至鼠标光标位置遇多显示器坐标匹配问题
AvalonDock(Dirkster版本):在ILayoutUpdateStrategy中设置浮动LayoutDocument至鼠标光标位置遇多显示器坐标匹配问题
我太懂你这种踩坐标坑的崩溃感了——AvalonDock(Dirkster版)的浮动窗口坐标逻辑和Windows系统的虚拟桌面坐标完全不是一套体系,多显示器分辨率不一样的时候,错位简直离谱。
你之前的思路其实没毛病:通过FloatingWidth/FloatingHeight/FloatingLeft/FloatingTop来定义窗口大小和位置,但核心矛盾点你也摸准了:
- Windows的
Cursor.Position返回的是虚拟桌面坐标:把所有显示器拼成一个大画布的全局坐标,不管每个显示器实际分辨率多少 - 而AvalonDock的
FloatingLeft/FloatingTop用的是单显示器的绝对物理像素坐标:以目标显示器左上角为原点的本地坐标
这就导致你直接赋值后,窗口会跑到完全不对的位置,尤其是多显示器分辨率差异大的时候。
给你个直接能用的解决方案,分步骤走:
第一步:把光标虚拟坐标转成目标屏幕的相对物理坐标
我们需要先找到光标当前所在的显示器,再计算光标相对于这个显示器左上角的偏移量,这样就能和AvalonDock的坐标体系对齐了。
代码示例(记得先引用System.Windows.Forms程序集):
int floatingWindowWidth = 500; int floatingWindowHeight = 300; // 1. 获取光标当前的虚拟坐标 var cursorWinPoint = new System.Drawing.Point(Cursor.Position.X, Cursor.Position.Y); // 2. 找到光标所在的显示器 var targetScreen = System.Windows.Forms.Screen.FromPoint(cursorWinPoint); // 3. 计算光标相对于目标显示器左上角的偏移量(这就是AvalonDock能识别的坐标基准) var relativeX = cursorWinPoint.X - targetScreen.Bounds.X; var relativeY = cursorWinPoint.Y - targetScreen.Bounds.Y; // 4. 让窗口中心对准光标,赋值给LayoutDocument layoutDocument.FloatingLeft = relativeX - floatingWindowWidth / 2; layoutDocument.FloatingTop = relativeY - floatingWindowHeight / 2; layoutDocument.FloatingWidth = floatingWindowWidth; layoutDocument.FloatingHeight = floatingWindowHeight;
第二步:(可选但重要)适配高DPI显示器
如果你的显示器开了DPI缩放(比如125%、150%),直接用物理像素会导致窗口大小/位置还是有偏差,这时候需要把物理坐标转换成WPF的设备独立像素(DIP):
// 先拿到当前窗口的DPI缩放比例(如果ILayoutUpdateStrategy里拿不到MainWindow,可以用LayoutDocument对应的Visual) var mainWindow = Application.Current.MainWindow; var dpiScale = VisualTreeHelper.GetDpi(mainWindow); var scaleX = dpiScale.DpiScaleX; var scaleY = dpiScale.DpiScaleY; // 把物理坐标和大小转换成DIP后再赋值 layoutDocument.FloatingLeft = (relativeX - floatingWindowWidth / 2) / scaleX; layoutDocument.FloatingTop = (relativeY - floatingWindowHeight / 2) / scaleY; layoutDocument.FloatingWidth = floatingWindowWidth / scaleX; layoutDocument.FloatingHeight = floatingWindowHeight / scaleY;
额外优化:防止窗口超出屏幕边界
如果光标太靠近屏幕边缘,窗口可能会被切到屏幕外面,可以加个简单的边界判断:
// 确保窗口左边界不超出屏幕 layoutDocument.FloatingLeft = Math.Max(0, layoutDocument.FloatingLeft); // 确保窗口上边界不超出屏幕 layoutDocument.FloatingTop = Math.Max(0, layoutDocument.FloatingTop); // 确保窗口右边界不超出屏幕 layoutDocument.FloatingLeft = Math.Min(targetScreen.Bounds.Width - floatingWindowWidth, layoutDocument.FloatingLeft); // 确保窗口下边界不超出屏幕 layoutDocument.FloatingTop = Math.Min(targetScreen.Bounds.Height - floatingWindowHeight, layoutDocument.FloatingTop);
这样调整后,浮动窗口就能精准地出现在光标位置,不管你有多少台分辨率不一样的显示器,都不会再错位了。
备注:内容来源于stack exchange,提问作者niyou
相关产品推荐
相关产品推荐

