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

WPF上下文菜单如何可能显示在窗口外?,wpf,windows,Wpf,Windows,据我所知,WPF应用程序中的控件不绑定到系统“窗口”资源(例如,使用Spy++无法找到它们的句柄),这与旧的Windows窗体应用程序不同 那么,这些菜单的一部分怎么可能显示在父窗口之外呢为什么不在它们到达窗口边界时立即切割? 当然,一种可能性是,它们不是真正的WPF菜单,而是标准的Windows资源。然而,这与我可以将其中一个菜单的样式设置为与任何其他WPF控件完全相同的事实相冲突,快速查看系统消息日志似乎可以确认,据Windows所知,它们实际上是相同的资源,具有相同的句柄 然后,我更进一步

据我所知,WPF应用程序中的控件不绑定到系统“窗口”资源(例如,使用Spy++无法找到它们的句柄),这与旧的Windows窗体应用程序不同

那么,这些菜单的一部分怎么可能显示在父窗口之外呢为什么不在它们到达窗口边界时立即切割?

当然,一种可能性是,它们不是真正的WPF菜单,而是标准的Windows资源。然而,这与我可以将其中一个菜单的样式设置为与任何其他WPF控件完全相同的事实相冲突,快速查看系统消息日志似乎可以确认,据Windows所知,它们实际上是相同的资源,具有相同的句柄

然后,我更进一步。我对菜单应用了旋转:

<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>

这是一个非常有趣的结果:


那么,这是怎么回事?

弹出窗口对象是普通
窗口
上任何“浮动”上下文的基础,例如上下文菜单、下拉列表等

实际上,
弹出窗口
实例创建了一个辅助Win32窗口,该窗口的目标是承载所需的WPF内容。实际上,
Popup
类利用了HwndSource互操作:

这也很有用:

但是,取而代之的是标准的Windows资源

这确实是一个标准的Windows窗口。就像你的主窗口一样。作为顶级窗口,它们可以任意重叠其他窗口


但您可以看到后果,空气空间问题,本机窗口无法旋转。它是一个基本的矩形,最多可以给它一个形状。这可能是一个通过旋转矩形来计算的形状,但WPF并没有走那么远。只有内容可以旋转。这在WPF中很容易做到,内容只是几层油漆,而不是Winforms中的本机窗口,因此旋转它只需要旋转变换。但是当然不能超出本机窗口的范围。

如果你在网上搜索WPF上下文菜单,你会发现很多文章指出
上下文菜单
与其父菜单不属于同一个视觉树

它们不是实际窗口的一部分,它们位于单独的窗口中。就像您可以在WPF中拥有多个窗口一样。ContextMenu和Popup的情况也是如此

ContextMenu只是一个弹出窗口。如果您有兴趣查看负责处理它的实际类是
System.Windows.Controls.Primitives.Popup
类,该类位于
PresentationFramework.dll
中。每当上下文菜单打开时,就会调用方法
CreateWindow

在关闭
DestroyWindow
时,调用方法来销毁为托管ContextMenu内容而创建的弹出窗口


因此,无论何时在包装下打开/关闭上下文菜单,都会创建并销毁一个窗口,该窗口显然不是主窗口的一部分,而是一个单独的窗口,可以超出主窗口边界。

FYI:这在展开时也适用于组合框。