什么方法可以阻止WPF Popup在屏幕外重新定位?

什么方法可以阻止WPF Popup在屏幕外重新定位?

我发现了这个老问题 ,但它没有得到正确答案。 有没有办法做到这一点? 如果有必要,我愿意将其子类化。 谢谢。

正如Andrei指出的那样,这种行为在Popup控件内部很深,很难克服。 如果您愿意做一些工作,可以通过调整弹出窗口内容到达屏幕边缘时进行调整。 出于演示的目的,我们将专注于屏幕的左边缘。

如果我们有这样的XAML:

      Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.     

和代码隐藏这样:

 private void Window_LocationChanged(object sender, EventArgs e) { RefreshPopupPosition(); } private void Window_SizeChanged(object sender, SizeChangedEventArgs e) { RefreshPopupPosition(); } private void RefreshPopupPosition() { var upperLeft = rectangle1.PointToScreen(new Point(0, 100)); var xOffset = Math.Min(0, upperLeft.X); popup1.Width = xOffset + 100; (popup1.Child as FrameworkElement).Margin = new Thickness(xOffset, 0, 0, 0); popup1.HorizontalOffset += 1; popup1.HorizontalOffset -= 1; } 

然后通过计算Popup将在屏幕外,我们可以减小内容的宽度并给它一个负边距,以便屏幕上的部分被剪切到Popup允许的情况下会出现的部分。

这必须扩展到处理屏幕的所有四个边缘和多个屏幕的可能性,但它表明该方法是可行的。

我认为没有办法做到这一点。 至少一个干净的方式。 如果您使用Reflector查看Popup类,您将找到一个UpdatePosition方法,该方法将调整弹出窗口的位置,使其保持在屏幕边界之间。 从几个地方调用此方法,从On***Changed回调( OnPlacementChangedOnVerticalOffsetChanged等)。

如果你真的想要获得这个function,你可能很少有机会扩展Popup类,覆盖使用On***Changed回调注册的属性上的一些元数据,这样UpdatePosition不会调用UpdatePosition ,但是大多数人会认为这是纯粹的邪恶,我也不推荐它。

在wpf框架上没有办法将Popup放在屏幕外,但你可以通过p / invoke调用“SetWindowPos”来强制弹出位置:

 #region P/Invoke imports & definitions private const int HWND_TOPMOST = -1; private const int HWND_NOTOPMOST = -2; private const int HWND_BOTTOM = 1; private const int SWP_NOMOVE = 0x0002; private const int SWP_NOSIZE = 0x0001; private const int SWP_NOACTIVATE = 0x0010; private const int GW_HWNDPREV = 3; private const int GW_HWNDLAST = 1; [DllImport("user32.dll", EntryPoint = "SetWindowPos")] private static extern int SetWindowPos(IntPtr hWnd, int hwndInsertAfter, int x, int y, int cx, int cy, int wFlags); #endregion private void updateposition(Item item) { if (item.IsOpen) { IntPtr hwnd = ((HwndSource)PresentationSource.FromVisual(item.popup.Child)).Handle; SetWindowPos(hwnd, 0, (int)item.WorkPoint.X, (int)item.WorkPoint.Y, (int)item.popup.Width, (int)item.popup.Height, SWP_NOSIZE | SWP_NOACTIVATE); } } 

您可以从我的opensource JungleControls库中使用PrecisePopup控件。 它将完全按照指定定位弹出窗口,即使这意味着弹出窗口部分偏离屏幕。

它可以从您定义的展示位置中自动选择最合适的展示位置,但如果您只需要一个与内置Popup的“底部”展示位置相对应的精确弹出式展示位置,则可以这样执行:

       

您必须将弹出窗口及其目标放在“canvas”面板中,以便由于弹出控件中的屏幕边缘问题而无法重新定位。

          

由于整个单元位于canvas面板内并且设置了放置矩形,因此弹出窗口将显示在矩形下方。