WPF 標準コントロールデモアプリ › Popup

Popup Overlays

Popup は、Child をアプリケーションの上に浮かぶ別のウィンドウに、別の要素を基準にして表示します。ComboBox や Menu のドロップダウンにも使われています。

子は別のウィンドウになる

Popup は FrameworkElement を継承しています。開いたとき、Child は Popup を置いたウィンドウの中には描かれません。子は独自のウィンドウハンドルを持ち、その親はポップアップ専用のルートの下にある内部のデコレーターでした。別のウィンドウなので、子はアプリケーションのウィンドウの外へ、さらに作業領域の下端の外へもはみ出せます。

また、アプリケーションのウィンドウには付いていきません。開いたままウィンドウを (40, 40) 動かしても、子は動きませんでした。ウィンドウが動いたらポップアップを閉じます。

ComboBox と最上位の MenuItem の既定のテンプレートには、PART_Popup という名前の Popup があり、独自のドロップダウンのコントロールも同じようにテンプレートの中に置けます。

閉じ方:StaysOpen の既定値は True

既定値は、IsOpen が False、StaysOpen が True、AllowsTransparency が False、Placement が Bottom、PopupAnimation が None です。IsOpen は既定で TwoWay にバインドされるため、ポップアップが自分で閉じると、バインドしたチェックボックスのチェックも外れます。

StaysOpen は、ほかの場所をクリックしても開いたままにするかどうかです。False では、実際のマウスでウィンドウの空いた場所をクリックするとポップアップが閉じ、IsOpen にバインドしたチェックボックスのチェックも外れました。True では同じクリックでも開いたままだったので、別の方法で閉じる必要があります。外側のクリックで閉じたい選択肢のパネルや補足の表示には、StaysOpen="False" を設定します。

透過と、アニメーションが動くかどうか

AllowsTransparency は、ポップアップのウィンドウを透過にできるかどうかです。True ではポップアップのウィンドウにレイヤードの属性(WS_EX_LAYERED)が付き、False では付きませんでした。

PopupAnimation が動くかどうかもこれで決まります。Fade で AllowsTransparency="True" のとき、ポップアップのルートの不透明度は、開いた直後にはまだ途中で(計測した回では開いて約 100 ms 後に 0.48。値は回ごとに変わります)、約 0.5 秒後に 1 になりました。False では最初から 1 で、フェードしませんでした。PopupAnimation には AllowsTransparency="True" を組み合わせます。

条件 計測値
基底クラス / IsOpen, StaysOpen, AllowsTransparency, Placement, PopupAnimation FrameworkElement / False, True, False, Bottom, None
既定のテンプレートの中の Popup: ComboBox / 最上位の MenuItem Popup PART_Popup / Popup PART_Popup
開いた状態: 子が別のウィンドウハンドルにあるか / 子の親 True / NonLogicalAdornerDecorator
StaysOpen=False、外側をマウスでクリック: IsOpen / バインドした CheckBox False / False
StaysOpen=True、外側をマウスでクリック: IsOpen / バインドした CheckBox True / True
開いた状態でウィンドウを (40, 40) 動かす: 子が動いた量 (0, 0)
AllowsTransparency=False、Fade: レイヤードウィンドウか / 開いた後の不透明度 False / 1(18 ms 時点), 1(76 ms 時点), 1(480 ms 時点)
AllowsTransparency=True、Fade: レイヤードウィンドウか / 開いた後の不透明度 True / 1(43 ms 時点), 0.48(97 ms 時点), 1(500 ms 時点)

既定値、別のウィンドウ、StaysOpen、透過。.NET 10 / Windows 11 で計測。

子が出る位置

Placement は、基準の要素に対して子をどこに出すかです。基準が 150 × 30、子が 120 × 40 のとき、基準の左上から見た子の左上は、Bottom で (0, 30)、Top で (0, -40)、Right で (150, 0)、Left で (-120, 0)、Center で中心がそろう (15, -5) でした。PlacementRectangle なしの Absolute では、子は画面の (0, 0) に出ました。

HorizontalOffset と VerticalOffset は、配置の後に加えるずらし量です。計測したどの配置でも、正の値で子は右と下へ動きました。Top と Left も同じです。(20, 10) を加えると、Top では (20, -30) と、基準に 10 近づきました。

出る側が固定だと思ってはいけません。画面の端で収まらないときは WPF が位置を変えますが、どう変えるかは Placement の値とどの端に接したかで異なります。基準を画面の下端の 10 上に置くと、Bottom でも子は基準の上に出ました。作業領域の下端の 10 上に置いたときは下に出て、作業領域の下端を越えました。

PlacementTarget は明示します。ないと、Popup を置いた要素が基準になり、200 × 60 の Grid に置いた Popup を Bottom にすると、子は Grid から見て (0, 60) に出ました。PlacementRectangle は基準の要素の範囲の代わりに使う矩形で、(0, 0, 100, 50) では、子は矩形の下の (0, 50) に出ました。

条件 計測値
Placement=Bottom: 基準の要素から見た子の位置 / オフセット (20, 10) を加えたとき (0, 30) / (20, 40)
Placement=Top: 基準の要素から見た子の位置 / オフセット (20, 10) を加えたとき (0, -40) / (20, -30)
Placement=Right: 基準の要素から見た子の位置 / オフセット (20, 10) を加えたとき (150, 0) / (170, 10)
Placement=Left: 基準の要素から見た子の位置 / オフセット (20, 10) を加えたとき (-120, 0) / (-100, 10)
Placement=Center: 基準の要素から見た子の位置 / オフセット (20, 10) を加えたとき (15, -5) / (35, 5)
Bottom、基準の要素を作業領域の下端の 10 上に置く: 子の位置 / 子の下端がはみ出す量 (0, 30) / 30
Bottom、基準の要素を画面の下端の 10 上に置く: 子の位置 / 子の下端がはみ出す量 (0, -40) / -40
Placement=Absolute、PlacementRectangle なし: 画面上の子の位置 (0, 0)
PlacementTarget なし、Bottom、200 x 60 の Grid の中の Popup: Grid から見た子の位置 (0, 60)
PlacementRectangle (0, 0, 100, 50) あり: Grid から見た子の位置 (0, 50)

配置ごとに子が出る位置。.NET 10 / Windows 11 で計測。

デモアプリで試す

デモアプリの Popup のページ。左にコントロールの一覧、右に最初の節の IsOpen / StaysOpen / AllowsTransparency

デモアプリの Popup のページには、IsOpen・StaysOpen・AllowsTransparency(IsOpen はチェックボックスにバインド)、位置とずらし量、PopupAnimation(ポップアップに AllowsTransparency="True" を設定)、Child と PlacementRectangle(ポップアップに PlacementTarget がなく、矩形 (0, 0, 100, 50) を使用)の 4 つの欄があります。各欄の下の「Show Code」リンクで、その欄の XAML を表示できます。次の XAML は、最初の欄(PopupUsageControl.xaml)から、スタイルと周囲の GroupBox を省き、名前空間の宣言を加えたものです。

<StackPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <CheckBox x:Name="IsOpenCheckBox" Content="IsOpen" />
  <CheckBox x:Name="StaysOpenCheckBox" Content="StaysOpen" IsChecked="True" />
  <CheckBox x:Name="AllowsTransparencyCheckBox" Content="AllowsTransparency" IsChecked="True" />

  <Grid>
    <Button x:Name="BasicPlacementTarget" Content="Placement Target" />
    <Popup x:Name="BasicPopup"
           AllowsTransparency="{Binding IsChecked, ElementName=AllowsTransparencyCheckBox}"
           IsOpen="{Binding IsChecked, ElementName=IsOpenCheckBox}"
           Placement="Bottom"
           PlacementTarget="{Binding ElementName=BasicPlacementTarget}"
           StaysOpen="{Binding IsChecked, ElementName=StaysOpenCheckBox}">
      <Border Background="White" BorderBrush="Gray" BorderThickness="1">
        <TextBlock Text="Basic Popup Content" />
      </Border>
    </Popup>
  </Grid>
</StackPanel>

関連するコントロールと記事

ソースコードと計測の方法

このページの挙動の記述は、すべて .NET 10 / Windows 11 で実際に動かして確かめたものです。計測には、このサイトのスクリーンショット生成ツールの PopupDemoScene を使いました。位置は、子と基準の要素の画面上の位置の差を、デバイスに依存しないピクセルで表しています。ポップアップの外側のクリックは、計測用のウィンドウの空いた場所を実際のマウスでクリックして行いました。

GitHub で Popup のソースコードを見る →