Popup 放置行为

Popup 控件在一个浮动在应用程序上的单独窗口中显示内容。 可以通过使用下列属性指定 Popup 相对于控件、鼠标或屏幕的位置:PlacementTargetPlacementPlacementRectangleHorizontalOffsetVerticalOffset。 这些属性协同工作,为您指定 Popup 的位置提供了灵活性。

注意注意

此外,ToolTipContextMenu 类也定义了这五个属性,并且这两个类的行为是类似的。

本主题包括下列各节。

  • 定位 Popup
  • 术语定义:Popup 分析
  • 这些属性如何协同工作
  • 当 Popup 到达屏幕边缘时
  • 相关主题

定位 Popup

Popup 的放置可相对于 UIElement 或整个屏幕。 下面的示例创建了相对于 UIElement(在此例中为图像)的四个 Popup 控件。 所有这些 Popup 控件所具有的 PlacementTarget 属性均设置为 image1,但其中每个 Popup 的 Placement 属性都具有不同的值。

<Canvas Width="200" Height="150">
  <Image Name="image1"
         Canvas.Left="75" 
         Source="Water_lilies.jpg" Height="200" Width="200"/>
  <Popup IsOpen="True" PlacementTarget="{Binding ElementName=image1}"
         Placement="Bottom">
    <TextBlock FontSize="14" Background="LightGreen">Placement=Bottom</TextBlock>

  </Popup>
  <Popup IsOpen="True" PlacementTarget="{Binding ElementName=image1}"
         Placement="Top">
    <TextBlock FontSize="14" Background="LightGreen">Placement=Top</TextBlock>

  </Popup>
  <Popup IsOpen="True" PlacementTarget="{Binding ElementName=image1}"
         Placement="Left">
    <TextBlock FontSize="14" Background="LightGreen">Placement=Left</TextBlock>

  </Popup>
  <Popup IsOpen="True" PlacementTarget="{Binding ElementName=image1}"
         Placement="Right">
    <TextBlock FontSize="14" Background="LightGreen">Placement=Right</TextBlock>

  </Popup>
</Canvas>

下图显示了该图像和这些 Popup 控件。

包含四个 Popup 的图像

具有四个弹出控件的图像

此简单示例演示如何设置 PlacementTargetPlacement 属性,但通过使用 PlacementRectangleHorizontalOffsetVerticalOffset 属性,可以对 Popup 的定位位置进行更多控制。

术语定义:Popup 分析

以下各项术语对了解 PlacementTargetPlacementPlacementRectangleHorizontalOffsetVerticalOffset 属性之间的相互关系以及它们与 Popup 之间的关系十分有用:

  • 目标对象

  • 目标区域

  • 目标原点

  • Popup 对齐点

这些术语为了解 Popup 的各个方面及其关联的控件提供了一种便捷的方法。

目标对象

目标对象是与 Popup 关联的元素。 如果设置了 PlacementTarget 属性,则该属性会指定目标对象。 如果未设置 PlacementTarget,而 Popup 具有父级,则该父级即是目标对象。 如果 PlacementTarget 值和父级都不存在,则没有目标对象,并且 Popup 将相对于屏幕进行定位。

下面的示例创建 Canvas 的子级 Popup。 此示例不为 Popup 设置 PlacementTarget 属性。 Placement 的默认值为 PlacementMode.Bottom,因此 Popup 会显示在 Canvas 下方。

<Canvas Margin="5" Background="Red" Width="200" Height="150" >

  <Ellipse Canvas.Top="60" Canvas.Left="50"
           Height="85" Width="60" 
           Fill="Black"/>

  <Popup IsOpen="True" >
    <TextBlock Background="LightBlue" FontSize="18">This is a Popup</TextBlock>
  </Popup>
</Canvas>

下图显示出 Popup 是相对于 Canvas 进行定位的。

没有 PlacementTarget 的 Popup

没有 PlacementTarget 的 Popup 控件

下面的示例创建 Canvas 的子级 Popup,但此时 PlacementTarget 已设置为 ellipse1,因此 Popup 会显示在 Ellipse 下方。

<Canvas Margin="5" Background="Red" Width="200" Height="150" >

  <Ellipse Name="ellipse1"
           Canvas.Top="60" Canvas.Left="50"
           Height="85" Width="60" 
           Fill="Black"/>

  <Popup IsOpen="True" PlacementTarget="{Binding ElementName=ellipse1}">
    <TextBlock Background="LightBlue" FontSize="18">This is a Popup</TextBlock>
  </Popup>
</Canvas>

下图显示出 Popup 是相对于 Ellipse 进行定位的。

具有 PlacementTarget 的 Popup

相对于椭圆定位的 Popup

注意注意

对于 ToolTipPlacement 的默认值为 Mouse。对于 ContextMenuPlacement 的默认值为 MousePoint。这些值将在后面的“这些属性如何协同工作”中进行说明。

目标区域

目标区域是屏幕上 Popup 所相对的区域。 在前面的示例中,Popup 与目标对象的边界对齐,但在有些情况下,Popup 与其他边界对齐,即使 Popup 具有目标对象也是如此。 如果设置了 PlacementRectangle 属性,目标区域就不同于目标对象的边界。

下面的示例创建两个 Canvas 对象,其中每个对象都包含一个 Rectangle 和一个 Popup。 在这两种情况下,Popup 的目标对象为 Canvas。 第一个 Canvas 中的 Popup 设置了 PlacementRectangle 属性,该属性的 XYWidthHeight 属性分别设置为 50、50、50 和 100。 第二个 Canvas 中的 Popup 没有设置 PlacementRectangle。 因此,第一个 Popup 位于 PlacementRectangle 下方,而第二个 Popup 则位于 Canvas 下方。 此外,每个 Canvas 还分别包含一个 Rectangle,它与第一个 PopupPlacementRectangle 具有相同的边界。 请注意,PlacementRectangle 属性不会在应用程序中创建可视元素;为此,此示例创建了 Rectangle 来表示 PlacementRectangle

<StackPanel Orientation="Horizontal" Margin="50,50,0,0">

  <Canvas Width="200" Height="200" Background="Red">
    <Rectangle Canvas.Top="50" Canvas.Left="50" 
               Width="50" Height="100"
               Stroke="White" StrokeThickness="3"/>
    <Popup IsOpen="True" PlacementRectangle="50,50,50,100">
      <TextBlock FontSize="14" Background="Yellow"
                 Width="140" TextWrapping="Wrap">
        This is a popup with a PlacementRectangle.
      </TextBlock>
    </Popup>
  </Canvas>

  <Canvas Width="200" Height="200" Background="Red" Margin="30,0,0,0">
    <Rectangle Canvas.Top="50" Canvas.Left="50" 
               Width="50" Height="100"
               Stroke="White" StrokeThickness="3"/>
    <Popup IsOpen="True">
      <TextBlock FontSize="14" Background="Yellow"
                 Width="140" TextWrapping="Wrap">
        This is a popup without a PlacementRectangle.
      </TextBlock>
    </Popup>
  </Canvas>

</StackPanel>

下图显示了上述示例的结果。

具有和没有 PlacementRectangle 的 Popup

具有和没有 PlacementRectangle 的 Popup

目标原点和 Popup 对齐点

目标原点和 Popup 对齐点分别是目标区域和 Popup 上用于定位的参考点。 可使用 HorizontalOffsetVerticalOffset 属性指定 Popup 相对于目标区域的偏移量。 HorizontalOffsetVerticalOffset 针对的是目标原点和 Popup 对齐点。 Placement 属性的值确定目标原点和 Popup 对齐点的位置。

下面的示例将创建一个 Popup,并将 HorizontalOffsetVerticalOffset 属性设置为 20。 此示例将 Placement 属性设置为 Bottom(默认值),因此目标原点位于目标区域的左下角,而 Popup 对齐点则位于 Popup 的左上角。

<Canvas Width="200" Height="200" Background="Yellow" Margin="20">
  <Popup IsOpen="True" Placement="Bottom"
         HorizontalOffset="20" VerticalOffset="20">
    <TextBlock FontSize="14" Background="#42F3FD">
      This is a popup.
    </TextBlock>
  </Popup>
</Canvas>

下图显示了上述示例的结果。

具有 HorizontalOffset 和 VerticalOffset 的 Popup

以目标原点为对齐点的 Popup 定位

这些属性如何协同工作

您需要同时考虑 PlacementTargetPlacementRectanglePlacement 的值,才能确定正确的目标区域、目标原点和 Popup 对齐点。 例如,如果 Placement 的值为 Mouse,则没有目标对象,将忽略 PlacementRectangle,并且目标区域是鼠标指针的边界。 相反,如果 PlacementBottom,则 PlacementTarget 或父对象会确定目标对象,而 PlacementRectangle 会确定目标区域。

下表描述了目标对象、目标区域、目标原点和 Popup 对齐点,并指示每个 PlacementMode 枚举值是否使用 PlacementTargetPlacementRectangle

PlacementMode

目标对象

目标区域

目标原点

Popup 对齐点

Absolute

不适用。 将忽略 PlacementTarget

屏幕或 PlacementRectangle(如果设置后者)。 PlacementRectangle 是相对于屏幕的。

目标区域的左上角。

Popup 的左上角。

AbsolutePoint

不适用。 将忽略 PlacementTarget

屏幕或 PlacementRectangle(如果设置后者)。 PlacementRectangle 是相对于屏幕的。

目标区域的左上角。

Popup 的左上角。

Bottom

PlacementTarget 或父对象。

目标对象或 PlacementRectangle(如果设置后者)。 PlacementRectangle 是相对于目标对象的。

目标区域的左下角。

Popup 的左上角。

Center

PlacementTarget 或父对象。

目标对象或 PlacementRectangle(如果设置后者)。 PlacementRectangle 是相对于目标对象的。

目标区域的中心。

Popup 的中心。

Custom

PlacementTarget 或父对象。

目标对象或 PlacementRectangle(如果设置后者)。 PlacementRectangle 是相对于目标对象的。

CustomPopupPlacementCallback 定义。

CustomPopupPlacementCallback 定义。

Left

PlacementTarget 或父对象。

目标对象或 PlacementRectangle(如果设置后者)。 PlacementRectangle 是相对于目标对象的。

目标区域的左上角。

Popup 的右上角。

Mouse

不适用。 将忽略 PlacementTarget

鼠标指针的边界。 将忽略 PlacementRectangle

目标区域的左下角。

Popup 的左上角。

MousePoint

不适用。 将忽略 PlacementTarget

鼠标指针的边界。 将忽略 PlacementRectangle

目标区域的左上角。

Popup 的左上角。

Relative

PlacementTarget 或父对象。

目标对象或 PlacementRectangle(如果设置后者)。 PlacementRectangle 是相对于目标对象的。

目标区域的左上角。

Popup 的左上角。

RelativePoint

PlacementTarget 或父对象。

目标对象或 PlacementRectangle(如果设置后者)。 PlacementRectangle 是相对于目标对象的。

目标区域的左上角。

Popup 的左上角。

Right

PlacementTarget 或父对象。

目标对象或 PlacementRectangle(如果设置后者)。 PlacementRectangle 是相对于目标对象的。

目标区域的右上角。

Popup 的左上角。

Top

PlacementTarget 或父对象。

目标对象或 PlacementRectangle(如果设置后者)。 PlacementRectangle 是相对于目标对象的。

目标区域的左上角。

Popup 的左下角。

以下各图针对每个 PlacementMode 值,显示了 Popup、目标区域、目标原点和 Popup 对齐点。 在每个图中,目标区域为黄色,而 Popup 为蓝色。

Placement 为 Absolute 或 AbsolutePoint

采用 Absolute 或 AbsolutePoint 定位的 Popup

Placement 为 Bottom

采用 Bottom 定位的 Popup

Placement 为 Center

采用 Center 定位的 Popup

Placement 为 Left

采用 Left 定位的 Popup

Placement 为 Mouse

采用 Mouse 定位的 Popup

Placement 为 MousePoint

采用 MousePoint 定位的 Popup

Placement 为 Relative 或 RelativePoint

采用 Relative 或 RelativePoint 定位的 Popup

Placement 为 Right

采用 Right 定位的 Popup

Placement 为 Top

采用 Top 定位的 Popup

当 Popup 到达屏幕边缘时

出于安全方面的考虑,Popup 不能被屏幕边缘隐藏。 当 Popup 到达屏幕边缘时,会发生以下三种行为之一:

  • Popup 会将自己沿屏幕边缘重新对齐,这会使 Popup 不可见。

  • Popup 使用其他 Popup 对齐点。

  • Popup 使用其他目标原点和 Popup 对齐点。

这些选项将在本节后面进行进一步说明。

Popup 到达屏幕边缘时的行为取决于 Placement 属性值以及 Popup 所到达的屏幕边缘。 下表针对每个 PlacementMode 值,概括了 Popup 到达屏幕边缘的行为。

PlacementMode

上边缘

下边缘

左边缘

右边缘

Absolute

与上边缘对齐。

与下边缘对齐。

与左边缘对齐。

与右边缘对齐。

AbsolutePoint

与上边缘对齐。

Popup 对齐点更改为 Popup 的左下角。

与左边缘对齐。

Popup 对齐点更改为 Popup 的右上角。

Bottom

与上边缘对齐。

目标原点更改为目标区域的左上角,而 Popup 对齐点更改为 Popup 的左下角。

与左边缘对齐。

与右边缘对齐。

Center

与上边缘对齐。

与下边缘对齐。

与左边缘对齐。

与右边缘对齐。

Left

与上边缘对齐。

与下边缘对齐。

目标原点更改为目标区域的右上角,而 Popup 对齐点更改为 Popup 的左上角。

与右边缘对齐。

Mouse

与上边缘对齐。

目标原点更改为目标区域(鼠标指针的边界)的左上角,而 Popup 对齐点更改为 Popup 的左下角。

与左边缘对齐。

与右边缘对齐。

MousePoint

与上边缘对齐。

Popup 对齐点更改为 Popup 的左下角。

与左边缘对齐。

Popup 对齐点更改为 Popup 的右上角。

Relative

与上边缘对齐。

与下边缘对齐。

与左边缘对齐。

与右边缘对齐。

RelativePoint

与上边缘对齐。

Popup 对齐点更改为 Popup 的左下角。

与左边缘对齐。

Popup 对齐点更改为 Popup 的右上角。

Right

与上边缘对齐。

与下边缘对齐。

与左边缘对齐。

目标原点更改为目标区域的左上角,而 Popup 对齐点更改为 Popup 的右上角。

Top

目标原点更改为目标区域的左下角,而 Popup 对齐点更改为 Popup 的左上角。 实际上,这与 PlacementBottom 时的情况相同。

与下边缘对齐。

与左边缘对齐。

与右边缘对齐。

与屏幕边缘对齐

Popup 可通过重新定位自身与屏幕边缘对齐,以便整个 Popup 都可显示在屏幕上。 达到这一效果后,目标原点与 Popup 对齐点之间的距离可能不同于 HorizontalOffsetVerticalOffset 的值。 如果 PlacementAbsoluteCenterRelative,则 Popup 会将其自身与每个屏幕边缘对齐。 例如,假设 PopupPlacement 设置为 Relative,并将 VerticalOffset 设置为 100。 如果屏幕的下边缘隐藏了整个或部分 Popup,则 Popup 会沿屏幕的下边缘重新定位自身,并且目标原点与 Popup 对齐点之间的垂直距离小于 100。 下图演示了这一效果。

Popup 与屏幕边缘对齐

与屏幕边缘对齐的 Popup

更改 Popup 对齐点

如果 PlacementAbsolutePointRelativePointMousePoint,则当 Popup 到达屏幕下边缘或右边缘时,Popup 对齐点会发生更改。

下图演示当屏幕下边缘隐藏整个或部分 Popup 时,Popup 对齐点将变为 Popup 的左下角。

Popup 到达屏幕下边缘并且使 Popup 对齐点发生更改

由于底部屏幕边缘而产生的新对齐点

下图演示当 Popup 被屏幕右边缘隐藏起来时,Popup 对齐点将变为 Popup 的右上角。

Popup 到达屏幕右边缘并且使 Popup 对齐点发生更改

由于屏幕边缘而产生的新 Popup 对齐点

如果 Popup 到达屏幕的屏幕下边缘或右边缘,则 Popup 对齐点会变为 Popup 的右下角。

更改目标原点和 Popup 对齐点

如果 PlacementBottomLeftMouseRightTop,则当 Popup 到达某一屏幕边缘时,目标原点和 Popup 对齐点会发生更改。 导致位置更改的屏幕边缘取决于 PlacementMode 值。

下图演示当 PlacementBottom 并且 Popup 到达屏幕下边缘时,目标原点将变为目标区域的左上角,而 Popup 对齐点将变为 Popup 的左下角。

Placement 为 Bottom 并且 Popup 到达屏幕下边缘

由于底部屏幕边缘而产生的新对齐点

下图演示当 PlacementLeft 并且 Popup 到达屏幕左边缘时,目标原点将变为目标区域的右上角,而 Popup 对齐点将变为 Popup 的左上角。

Placement 为 Left 并且 Popup 到达屏幕左边缘

由于左侧屏幕边缘而产生的新对齐点

下图演示当 PlacementRight 并且 Popup 到达屏幕右边缘时,目标原点将变为目标区域的左上角,而 Popup 对齐点将变为 Popup 的右上角。

Placement 为 Right 并且 Popup 到达屏幕右边缘

由于右侧屏幕边缘而产生的新对齐点

下图演示当 PlacementTop 并且 Popup 到达屏幕上边缘时,目标原点将变为目标区域的左下角,而 Popup 对齐点将变为 Popup 的左上角。

Placement 为 Top 并且 Popup 到达屏幕上边缘

由于顶部屏幕边缘而产生的新对齐点

下图演示当 PlacementMouse 并且 Popup 到达屏幕下边缘时,目标原点将变为目标区域(鼠标指针的边界)的左上角,而 Popup 对齐点将变为 Popup 的左下角。

Placement 为 Mouse 并且 Popup 到达屏幕下边缘

由于鼠标接近屏幕边缘而产生的新对齐点

自定义 Popup 放置

您可以通过将 Placement 属性设置为 Custom,自定义目标原点和 Popup 对齐点。 然后,再定义一个 CustomPopupPlacementCallback 委托,该委托按优先顺序为 Popup 返回一组可能的位置点和主轴。 此时,显示 Popup 最大部分的点会被选中。 如果 Popup 被屏幕边缘隐藏起来,则会自动调整 Popup 的位置。 有关示例,请参见如何:指定自定义 Popup 位置

请参见

其他资源

Popup Placement Sample