WPF上下文菜单如何在窗口外显示?

3
据我所知,WPF应用程序中的控件不绑定系统“窗口”资源(例如,您无法使用Spy++找到它们的句柄),而旧的Windows Forms应用程序则不同。那么,这些菜单的一部分如何显示在父窗口外面呢?为什么它们没有在达到窗口边界时被裁剪?当然,一种可能性是它们并不是真正的WPF菜单,而是标准的Windows资源。但是,这与事实相冲突,即我可以像任何其他WPF控件一样精确地为其中一个菜单设置样式,并且对系统消息日志的快速查看似乎证实了它们实际上是完全相同的资源,具有相同的句柄。然后,我更进一步。我对菜单应用了旋转:
<Style TargetType="{x:Type ContextMenu}">
    <Setter Property="RenderTransformOrigin" Value="0.5,0.5" />
    <Setter Property="RenderTransform">
        <Setter.Value>
            <TransformGroup>
                <ScaleTransform/>
                <SkewTransform/>
                <RotateTransform Angle="-18.435"/>
                <TranslateTransform/>
            </TransformGroup>
        </Setter.Value>
    </Setter>
</Style>

以下是非常有趣的结果:

菜单被剪裁成矩形

那么,到底发生了什么?


请注意:当下拉框展开时,此内容同样适用。 - Emond
3个回答

5
如果你在网络上搜索WPF上下文菜单,你会发现很多文章都指出ContextMenu不属于其父级所在的视觉树。
它们并不是实际窗口的一部分,而是托管在单独的窗口中。就像你可以在WPF中叠加多个窗口一样。同样适用于上下文菜单和弹出窗口。
上下文菜单只是Popup。如果你有兴趣查看实际处理它的类,可以看到位于PresentationFramework.dll中的System.Windows.Controls.Primitives.Popup类。每当打开上下文菜单时,都会调用方法CreateWindow
关闭时会调用DestroyWindow方法来销毁用于托管ContextMenu内容的弹出窗口。
因此,每当上下文菜单在后台打开/关闭时,都会创建和销毁一个窗口,这显然不是主窗口的一部分,而是完全独立的窗口,可以超出主窗口边界。

4
但是,实际上它们是标准的Windows窗口资源。就像你的主窗口一样,它们是顶级窗口,可以随意重叠其他窗口。但是你可能会遇到一个“空气间问题”,即本机Windows窗口不能旋转。它是一个基本的矩形,最多只能赋予一个形状。这个形状可以通过旋转矩形来计算,但WPF没有做到那么细致。只有内容可以旋转,在WPF中,内容仅仅是涂层的堆积,并不像Winforms中那样成为本机窗口,因此旋转只需要进行旋转变换即可。但当然不能超出本机窗口的范围。

3
Popup对象是任何普通Window上方"浮动"上下文的基础,如上下文菜单,下拉列表等。
事实上,Popup实例创建了一个次要的Win32窗口,该窗口旨在托管所需的WPF内容。实际上,Popup类利用了HwndSource互操作性: MSDN:HwndSource Class 这也很有用: Win32 Handle(HWND)和WPF对象

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