彈出視窗會在你應用程式中的其他 UI 上方顯示內容。
命名空間中的 Microsoft.UI.Xaml.Controls.Primitives 類別是該內容的通用容器。 它沒有預設的視覺模板,所以你提供內容、外觀,以及開啟和關閉它的邏輯。
Popup 是一個低階的建構單元。 WinUI 也提供常見的暫態介面控制項,例如彈出視窗、對話方塊、教學提示及工具提示。 這些控制項包括其自身的樣式、位置和關閉行為。
這是正確的控制嗎?
如果有更高層次的控制符合你的情境,就不要使用 Popup。 改用以下控制方式:
| Scenario | 控制 |
|---|---|
| 在使用者點擊其外部時會關閉的介面中,顯示資訊或收集與某個項目相關的輸入。 | 飛出視窗 |
| 顯示指令或選項清單。 | MenuFlyout |
| 提出問題,或展示使用者必須回應的資訊,才能繼續。 | 內容對話 |
| 指出一個新的或重要的特徵,無論是否針對特定元素。 | 教學小技巧 |
| 當使用者將滑鼠移到某元素上或將焦點移到該元素時,請顯示該元素的簡短描述。 | 工具提示 |
當你需要浮在 UI 上方的自訂內容,但這些控制項都不符合你需求時,就用 a Popup 。 例如,你可以用彈出視窗來實作覆蓋層,自己做樣式和擺放。
彈出視窗不是模態的,所以使用者仍然可以與背後的使用者介面互動。 如果使用者必須先回應才能繼續,請使用 ContentDialog。
Recommendations
- 給彈出視窗內容背景、邊框和圓角,讓它從背後的介面中脫穎而出。 WinUI 3 圖庫範例使用
AcrylicBackgroundFillColorDefaultBrush、SurfaceStrokeColorDefaultBrush和OverlayCornerRadius資源。 更多資訊請參考 壓克力材質 和 彈出視窗中的 ThemeShadow。 - 如果你沒有啟用 點擊外部關閉,可以加上一個按鈕或其他控制項來關閉彈出視窗。
- 保持彈出式內容簡短,專注於單一任務。
建立快顯視窗
![]()
WinUI 3 圖庫應用程式包含互動式的 WinUI 控制項與功能範例。 你可以從 Microsoft Store 下載應用程式,或瀏覽 GitHub 的原始碼。
彈出視窗會承載一個元素,你可以將其設為 Child。 子項目通常是面板,或是用來定義彈出式視窗內容的 UserControl。 要顯示彈出視窗,請將 IsOpen 設為 true。 要隱藏它,請設 IsOpen 為 false。
此範例基於 WinUI 3 圖庫範例。 它會在開啟彈出視窗的按鈕旁宣告一個彈出視窗,而彈出視窗內容中包含一個關閉彈出視窗的按鈕。
<Grid HorizontalAlignment="Left" VerticalAlignment="Top">
<Button Content="Show popup" Click="ShowPopupClicked" />
<Popup x:Name="StandardPopup" HorizontalOffset="200" VerticalOffset="0">
<Grid MinWidth="240"
Padding="16"
Background="{ThemeResource AcrylicBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource SurfaceStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="{StaticResource OverlayCornerRadius}">
<StackPanel Spacing="8">
<TextBlock FontSize="16" Text="Simple popup" />
<Button Content="Close" Click="ClosePopupClicked" />
</StackPanel>
</Grid>
</Popup>
</Grid>
// Opens the popup if it isn't already open.
private void ShowPopupClicked(object sender, RoutedEventArgs e)
{
if (!StandardPopup.IsOpen)
{
StandardPopup.IsOpen = true;
}
}
// Closes the popup when the user clicks the Close button inside it.
private void ClosePopupClicked(object sender, RoutedEventArgs e)
{
if (StandardPopup.IsOpen)
{
StandardPopup.IsOpen = false;
}
}
以程式碼建立快顯視窗
你也可以用程式碼建立一個彈出視窗,而不將其加入視覺樹。 你在 XAML 中宣告或新增到視覺樹中的面板的彈出視窗,其 XamlRoot 會從其父元素取得。 沒有父項的彈出式視窗不會自動設定這個屬性,所以你必須在開啟之前先設定它的 XamlRoot 屬性。
private Popup? _popup;
private void ShowPopupFromCodeClicked(object sender, RoutedEventArgs e)
{
_popup ??= new Popup
{
// PopupContent is a UserControl in your app that defines the popup content.
Child = new PopupContent(),
IsLightDismissEnabled = true,
// Required because this popup isn't in the visual tree. Use the XamlRoot
// of an element that's already loaded, such as the button that was clicked.
XamlRoot = ((UIElement)sender).XamlRoot
};
_popup.IsOpen = true;
}
Important
在 WinUI 3 中,開啟既沒有父元素,也沒有 XamlRoot 的快顯視窗會失敗。 元素的 XamlRoot 為 null,直到該元素加入即時視覺樹,所以應該從已經載入的元素取得值,而不是在頁面建構器中。 在 Window 類別中,你可以使用 this.Content.XamlRoot。 更多資訊請參閱 ContentDialog 和 Popup。
Note
不在視覺樹中的彈出視窗,觸控鍵盤出現時不會自動重新定位,所以鍵盤可以遮住它。 如果彈出視窗包含文字輸入控制項,例如 TextBox,請在 XAML 中宣告該彈出視窗,或將其加入視覺樹中的面板。
以輕觸關閉彈出視窗
預設情況下,彈出視窗會一直開啟,直到你的程式碼設定 IsOpen 為 false。 將 IsLightDismissEnabled 設為 true,讓使用者在彈出視窗外按一下或輕觸,或按下 Esc 鍵時關閉彈出視窗。 這種行為稱為 輕觸即關閉。
預設情況下,點擊外部即可關閉的快顯視窗外部區域不會變暗。 要讓它變暗,請將 LightDismissOverlayMode 設為 On。 當 IsLightDismissEnabled 為 時 false,此性質無影響。
<Popup x:Name="LightDismissPopup"
IsLightDismissEnabled="True"
LightDismissOverlayMode="On">
<Border Padding="16"
Background="{ThemeResource AcrylicBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource SurfaceStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="{StaticResource OverlayCornerRadius}">
<TextBlock Text="Click outside this popup or press Esc to close it." />
</Border>
</Popup>
放置快顯視窗
你可以用偏移來定位彈出視窗,或相對於另一個元素來定位。
使用偏移量
HorizontalOffset 和 VerticalOffset 會設定彈出視窗的位置,單位是像素。 偏移量的測量點取決於彈出視窗是否有父節點:
- 視覺樹中的彈出視窗在其父項版面配置中,會偏離自身的位置。 例如,在垂直方向
StackPanel中,該位置位於彈出視窗前的元素下方。 在 第一個例子中,彈出視窗與按鈕共用一個單元Grid格,因此它看起來位於Grid的左上角右側 200 像素的位置。 - 沒有父節點的彈出視窗,例如你 在程式碼中建立的,會相對於其 XAML 根目錄的左上角偏移,而該根目錄通常是你應用程式視窗的內容區域。
在元素旁邊放置彈出視窗
要在特定元素旁邊顯示彈出視窗,請將 PlacementTarget 設為該元素。 接著將 DesiredPlacement 設定為不是 Auto 的 PopupPlacementMode 值,例如 Bottom 或 RightEdgeAlignedTop。
當彈出視窗打開時,框架會將其相對於目標元素定位。 如果彈出視窗無法放在理想位置,框架會將其移到目標的另一側。
HorizontalOffset 和 VerticalOffset 仍然適用,並將快顯視窗從計算出的位置移開。
ActualPlacement 會回報彈出視窗顯示的位置。 當該值在彈出視窗開啟時變更時,ActualPlacementChanged 事件就會發生。
<StackPanel Spacing="8">
<Button x:Name="DetailsButton" Content="Show details" Click="ShowDetailsClicked" />
<TextBlock x:Name="PlacementStatus" />
<Popup x:Name="DetailsPopup"
PlacementTarget="{x:Bind DetailsButton}"
DesiredPlacement="BottomEdgeAlignedLeft"
IsLightDismissEnabled="True"
ActualPlacementChanged="DetailsPopup_ActualPlacementChanged">
<Border Padding="16"
Background="{ThemeResource AcrylicBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource SurfaceStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="{StaticResource OverlayCornerRadius}">
<TextBlock Text="This popup appears below the button when there's room." />
</Border>
</Popup>
</StackPanel>
private void ShowDetailsClicked(object sender, RoutedEventArgs e)
{
DetailsPopup.IsOpen = true;
}
private void DetailsPopup_ActualPlacementChanged(object sender, object e)
{
// ActualPlacement differs from DesiredPlacement when the popup
// doesn't fit in the preferred position.
PlacementStatus.Text = $"Actual placement: {DetailsPopup.ActualPlacement}";
}
在應用程式視窗外顯示彈出視窗
預設情況下,彈出視窗會限制在其 XAML 根節點的範圍內,這通常是你應用程式視窗中的內容區域。 從 Windows 應用程式 SDK 1.4 開始,你可以將 ShouldConstrainToRootBounds 設為 false,讓彈出視窗延伸到視窗之外。 例如,當彈出視窗比小視窗大時,你可以這麼做。
在你第一次打開彈出視窗前就設定 ShouldConstrainToRootBounds 好。 彈出視窗開啟後你無法更改。
<Popup x:Name="UnconstrainedPopup" ShouldConstrainToRootBounds="False">
<!-- Popup content -->
</Popup>
為彈出式視窗加入動畫
要在彈出視窗內容出現時加入動畫效果,請在 ChildTransitions 集合中加入轉場。 PopupThemeTransition 提供彈出式介面的動畫,例如類似工具提示的內容,當畫面出現時。
<Popup x:Name="AnimatedPopup" IsLightDismissEnabled="True">
<Popup.ChildTransitions>
<TransitionCollection>
<PopupThemeTransition />
</TransitionCollection>
</Popup.ChildTransitions>
<Border Padding="16"
Background="{ThemeResource AcrylicBackgroundFillColorDefaultBrush}"
BorderBrush="{ThemeResource SurfaceStrokeColorDefaultBrush}"
BorderThickness="1"
CornerRadius="{StaticResource OverlayCornerRadius}">
<TextBlock Text="This content animates when the popup opens." />
</Border>
</Popup>
若要改為從分鏡腳本控制顯示與隱藏動畫,請使用 PopInThemeAnimation 和 PopOutThemeAnimation。 更多資訊請參閱 顯示/隱藏彈窗。
當彈窗開啟或關閉時回應
Opened 事件會在 IsOpen 設定為 true 時發生。 當 false 設定為 IsOpen 時,就會發生 Closed 事件,包括彈出視窗透過輕觸關閉時。 用 Closed 來處理無論彈出式視窗如何關閉都必須完成的工作。 例如,WinUI 3 Gallery 範例會使用 Closed 重新啟用一個設定,而該範例會在快顯視窗開啟時停用該設定。
兩個事件都使用 EventHandler<object>,因此你的處理常式接受一個 object 發送者和一個 object 事件參數。
<StackPanel Spacing="8">
<TextBlock x:Name="StatusText" />
<Popup x:Name="StatusPopup"
IsLightDismissEnabled="True"
Opened="StatusPopup_Opened"
Closed="StatusPopup_Closed">
<!-- Popup content -->
</Popup>
</StackPanel>
private void StatusPopup_Opened(object sender, object e)
{
StatusText.Text = "The popup is open.";
}
private void StatusPopup_Closed(object sender, object e)
{
// Closed occurs for every close, including light dismiss.
StatusText.Text = "The popup is closed.";
}
鍵盤、焦點與無障礙
- 啟用輕觸關閉時,打開彈出視窗會將焦點移到該視窗,關閉彈出視窗則會將焦點回到之前有焦點的元素。 使用者也可以按 Esc 鍵關閉彈出視窗。
- 當未啟用輕觸關閉時,彈出視窗開啟時不會移動焦點。 打開彈出視窗後,將焦點移到某個元素上,加入一個鍵盤使用者可以觸及的 關閉 按鈕,關閉後再將焦點回到開啟該彈窗的元素。
- 彈出視窗不會引發路由事件,例如
KeyDown和PointerPressed。 要處理這些事件,請將處理器附加到彈出視窗的子元素上。 - 確保彈出視窗中的每個互動元素都有一個可存取的名稱。 欲了解更多資訊,請參閱 鍵盤無障礙 及 揭露基本無障礙資訊。