为什么 WPF 中的 Popup PlacementRectangle 会导致裁剪?

3
在我正在开发的WPF应用程序中,地图上有图标,当单击时会显示一个弹出式上下文菜单。由于我想将上下文菜单与图标对齐,所以我使用了PlacementRectangle与图标图像的矩形和Placement.Bottom
这通常有效,但其中一些图标的上下文菜单超过了屏幕高度的一半(在1024x768屏幕上),并且当靠近屏幕边缘时,弹出式窗口在对齐后被裁剪。
我已经多次阅读了docs,但没有看到我看到的行为的解释。具体来说,我看到的行为是:
当图标位于屏幕中心附近,但菜单无法适配在其下方时,弹出窗口会按预期翻转到图标顶部(目标原点和弹出对齐点发生变化)。当翻转导致弹出窗口的顶部超过屏幕顶部时,弹出窗口的顶部会按预期重新与屏幕对齐。然而,弹出窗口的底部边缘不会随着弹出窗口的其余部分向下移动,导致弹出窗口底部内容被裁剪(虽然有足够的空间来扩展)。这似乎违反了它最初被移动到屏幕边缘的原因(“出于安全考虑”...)。
docs中,我希望所有这些行为都是相同的,除了最后的裁剪,如果我使用Placement.MousePlacement.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;
    }

注意: 我尝试使用了一个PlacmentTarget并且得到了相同的裁剪行为。

1个回答

0

由于没有人回答这个问题,我也没有找到更多关于这个问题的信息,我猜测这是一个 bug。我已经找到了一个解决方法,并且想在这里发布,以防其他人遇到同样的问题:

使用自定义放置和放置回调可以模仿 Popup 的预期行为,并且不执行任何剪切:

    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 ),
    };
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接