为什么WPF弹出PlacementRectangle会导致剪切?
本文关键字:WPF 弹出 PlacementRectangle 为什么 | 更新日期: 2023-09-27 17:49:45
在我正在开发的WPF应用程序中,我在地图上有图标,当单击时在弹出框中显示上下文菜单。因为我想在图标下方对齐上下文菜单,所以我使用PlacementRectangle
与图标图像和Placement.Bottom
的矩形。
这在大多数情况下工作良好,但少数图标的上下文菜单超过屏幕高度的一半(在1024x768屏幕上),当接近屏幕边缘时,弹出框在与边缘对齐后被剪切。
我已经阅读了几次关于这个的文档,但没有看到我所看到的行为的解释。具体来说,我看到的行为是:
当图标接近屏幕中央,但太低而无法容纳菜单时,弹出框会按预期翻转到图标的顶部(Target Origin &弹出对齐点更改)。当结果翻转使弹出窗口的顶部超过屏幕的上边缘时,弹出窗口的顶部将按照预期与屏幕重新对齐。然而,弹出窗口的底部边缘不会随着弹出窗口的其余部分向下移动,从而导致弹出窗口的底部内容被剪切(虽然有足够的扩展空间)。这似乎违背了它首先被移到屏幕边缘的原因("出于安全考虑"…)。
从文档中,我希望所有这些行为都是相同的,除了最后的剪辑,如果我使用Placement.Mouse
或Placement.MousePoint
,整个弹出式正确移动。
我在msdn文档或谷歌搜索中找不到这种行为的解释,这是一个错误还是预期的行为?是否有一个解决方案或技巧使用PlacementRectangle和防止由此产生的剪切?
我创建了一个简单的WPF示例应用程序来演示这个问题。它只是一个带有画布的窗口,其中包含一个名为"Rec"的矩形。该代码有一个事件处理程序: private void Window_MouseDown( object sender, MouseButtonEventArgs e )
{
// get mouse coordinates at click
var c = Mouse.GetPosition(this);
var cs = PointToScreen(c);
// an image to visualize popup clipping
var img = new Image() { Source = new BitmapImage( new Uri( "pack://application:,,,/test.png" ) ) };
img.Width = 150;
img.Height = 500;
// visually show the placement rectangle
Canvas.SetLeft( Rec, c.X );
Canvas.SetTop( Rec, c.Y );
var p = new Popup()
{
Placement = PlacementMode.Bottom,
PlacementRectangle = new Rect( cs.X, cs.Y, 40, 60 ),
//Placement = PlacementMode.Mouse,
StaysOpen = false,
Child = img,
};
p.IsOpen = true;
}
注意:我尝试使用PlacementTarget并得到相同的剪切行为。
由于没有人回答这个问题,我还没有找到任何关于这个问题的更多信息,我猜这是一个错误。我已经找到了一个解决方案,我想我会发布,以防其他人遇到它:
使用带有放置回调的自定义放置可以让您模仿弹出框的预期行为,并且不执行任何剪切:
var p = new Popup()
{
PlacementRectangle = new Rect( cs.X, cs.Y, 40, 60 ),
Placement = PlacementMode.Custom,
CustomPopupPlacementCallback = new CustomPopupPlacementCallback( placePopup ),
StaysOpen = false,
Child = img,
};
和我使用的位置回调:
private CustomPopupPlacement[] placePopup( Size popupSize, Size targetSize, Point offset )
{
Debug.WriteLine( "{0}; {1}; {2}", popupSize.ToString(), targetSize.ToString(), offset.ToString() );
return new[] {
new CustomPopupPlacement( new Point( -50, targetSize.Height ), PopupPrimaryAxis.Vertical ),
new CustomPopupPlacement( new Point( -50, -popupSize.Height ), PopupPrimaryAxis.Vertical ),
};
}