對話方塊概觀 (WPF .NET)

Windows Presentation Foundation (WPF) 可讓您設計自己的對話方塊。 對話方塊是視窗,但具有特定意圖和使用者體驗。 本文探討對話方塊的運作方式,以及您可以建立和使用的對話方塊類型。 對話方塊可用來:

  • 對使用者顯示特定資訊。
  • 向使用者收集資訊。
  • 顯示並收集資訊。
  • 顯示作業系統提示,例如列印視窗。
  • 選取檔案或資料夾。

這些類型的視窗稱為「對話方塊」。 對話方塊可以透過兩種方式顯示:強制回應和非強制回應。

向使用者顯示「強制回應」對話方塊是一種技術,應用程式會使用該技術中斷其所執行的動作,直到使用者關閉對話方塊為止。 這通常以提示或警示的形式出現。 在關閉對話方塊之前,無法與應用程式中的其他視窗進行互動。 關閉「強制回應」對話方塊之後,應用程式就會繼續執行。 最常見的對話方塊是用來顯示開啟檔案或儲存檔案提示、顯示印表機對話方塊,或將某些狀態傳訊給使用者。

「非強制回應」對話方塊在開啟時,不會防止使用者啟動其他視窗。 例如,如果使用者想要尋找出現在文件中的特定字組,主視窗通常會開啟對話方塊,詢問使用者要尋找哪個字組。 由於應用程式不想防止使用者編輯文件,因此對話方塊不需要是強制回應。 非強制回應對話方塊至少會提供用來關閉對話方塊的 [關閉] 按鈕。 可能還提供其他按鈕來執行特定功能,例如提供 [尋找下一個] 按鈕以在文字搜尋中尋找下一個字組。

您可以使用 WPF 建立幾種類型的對話方塊,例如訊息方塊、通用對話方塊和自訂對話方塊。 本文將探討每種類型,而對話方塊範例 (英文) 會提供相符的範例。

訊息方塊

「訊息方塊」是可用來顯示文字資訊,並讓使用者透過按鈕做出決定的對話方塊。 下圖所示的訊息方塊會提出問題,並提供使用者三個按鈕來回答問題。

[文字處理器] 對話方塊,詢問您是否要在應用程式關閉之前儲存文件變更。

若要建立訊息方塊,您可以使用 MessageBox 類別。 MessageBox 可讓您設定訊息方塊的文字、標題、圖示和按鈕。

如需詳細資訊,請參閱如何開啟訊息方塊

通用對話方塊

Windows 會實作所有應用程式通用且可重複使用的不同類型對話方塊,包括用於選取檔案和列印的對話方塊。

由於這些對話方塊是由作業系統提供,因此這些對話方塊可在作業系統上執行的所有應用程式之間共用。 這些對話方塊提供一致的使用者體驗,稱為「通用對話方塊」。 當使用者在一個應用程式中使用通用對話方塊時,使用者不需要了解如何在其他應用程式中使用該對話方塊。

WPF 會封裝 [開啟檔案]、[儲存檔案]、[開啟資料夾] 和 [列印] 通用對話方塊,然後將這些對話方塊公開為受控類別以供您使用。

從 WPF 呼叫的 [開啟檔案] 對話方塊。

若要深入了解通用對話方塊,請參閱下列文章:

自訂對話方塊

雖然通用對話方塊很有用,而且應該盡可能使用,但這類對話方塊並不支援定義域專屬對話方塊的需求。 在此情況下,您必須建立自己的對話方塊。 如稍後所示,對話方塊是具有特殊行為的視窗。 Window 實作了這些行為,因此您會使用視窗來建立自訂的強制回應和非強制回應對話方塊。

當您建立自己的對話方塊時,需要考慮許多設計考量。 雖然應用程式視窗和對話方塊有相似之處 (例如共用相同的基底類別),但對話方塊會用於特定用途。 當您需要提示使用者輸入某種資訊或回應時,通常需要對話方塊。 一般而言,應用程式會在顯示對話方塊 (強制回應) 時暫停,以限制對應用程式其餘部分的存取。 關閉對話方塊之後,應用程式就會繼續執行。 不過,將互動僅限制在對話方塊並非必要。

WPF 視窗一經關閉,就無法重新開啟。 自訂對話方塊是 WPF 視窗,適用相同的規則。 若要了解如何關閉視窗,請參閱如何關閉視窗或對話方塊

實作對話方塊

設計對話方塊時,請遵循下列建議來建立良好的使用者體驗:

❌ 不要讓對話方塊視窗顯得雜亂無章。 對話方塊體驗是讓使用者輸入某些資料或做出選擇。

✔️ 務必提供 [確定] 按鈕來關閉視窗。

✔️ 務必將 [確定] 按鈕的 IsDefault 屬性設定為 true,以允許使用者按下 ENTER 鍵來接受並關閉視窗。

✔️ 考慮新增 [取消] 按鈕,讓使用者可以關閉視窗,並指出使用者不想繼續執行。

✔️ 務必將 [取消] 按鈕的 IsCancel 屬性設定為 true,以允許使用者按下 ESC 鍵來關閉視窗。

✔️ 務必設定視窗的標題,以正確描述對話方塊代表的內容,或使用者應該對對話方塊執行的動作。

✔️ 務必設定視窗的最小寬度和高度值,以防止使用者將視窗大小調整得太小。

✔️ 如果 ShowInTaskbar 設定為 false,請考慮停用調整視窗大小的功能。 藉由將 ResizeMode 設定為 NoResize,即可停用調整大小功能

下列程式碼示範這項設定。

<Window x:Class="Dialogs.Margins"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Change Margins"
        Closing="Window_Closing"
        MinHeight="200"
        MinWidth="300"
        SizeToContent="WidthAndHeight"
        ResizeMode="NoResize"
        ShowInTaskbar="False"
        WindowStartupLocation="CenterOwner" 
        FocusManager.FocusedElement="{Binding ElementName=leftMarginTextBox}">
    <Grid Margin="10">
        <Grid.Resources>
            <!-- Default settings for controls -->
            <Style TargetType="{x:Type Label}">
                <Setter Property="Margin" Value="0,3,5,5" />
                <Setter Property="Padding" Value="0,0,0,5" />
            </Style>
            <Style TargetType="{x:Type TextBox}">
                <Setter Property="Margin" Value="0,0,0,5" />
            </Style>
            <Style TargetType="{x:Type Button}">
                <Setter Property="Width" Value="70" />
                <Setter Property="Height" Value="25" />
                <Setter Property="Margin" Value="5,0,0,0" />
            </Style>
        </Grid.Resources>

        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition />
        </Grid.RowDefinitions>

        <!-- Left,Top,Right,Bottom margins-->
        <Label Grid.Column="0" Grid.Row="0">Left Margin:</Label>
        <TextBox Name="leftMarginTextBox" Grid.Column="1" Grid.Row="0" />

        <Label Grid.Column="0" Grid.Row="1">Top Margin:</Label>
        <TextBox Name="topMarginTextBox" Grid.Column="1" Grid.Row="1"/>

        <Label Grid.Column="0" Grid.Row="2">Right Margin:</Label>
        <TextBox Name="rightMarginTextBox" Grid.Column="1" Grid.Row="2" />

        <Label Grid.Column="0" Grid.Row="3">Bottom Margin:</Label>
        <TextBox Name="bottomMarginTextBox" Grid.Column="1" Grid.Row="3" />

        <!-- Accept or Cancel -->
        <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="4" Orientation="Horizontal" HorizontalAlignment="Right">
            <Button Name="okButton" Click="okButton_Click" IsDefault="True">OK</Button>
            <Button Name="cancelButton" IsCancel="True">Cancel</Button>
        </StackPanel>
    </Grid >
</Window>

上述 XAML 會建立類似下圖的視窗:

WPF 的對話方塊視窗,其中顯示左、上、右、下的文字方塊。

開啟對話方塊的 UI 元素

對話方塊的使用者體驗也會延伸至開啟對話方塊的視窗功能表列或按鈕。 當功能表項目或按鈕所執行的函式需要透過對話方塊進行使用者互動才能繼續執行時,控制項應該在其標頭文字的結尾處使用省略符號:

<MenuItem Header="_Margins..." Click="formatMarginsMenuItem_Click" />
<!-- or -->
<Button Content="_Margins..." Click="formatMarginsButton_Click" />

若功能表項目或按鈕所執行的函式顯示需要使用者互動的對話方塊 (例如 [關於] 對話方塊),則不需要省略符號。

功能表項目是為使用者提供應用程式動作的常見方式,這些動作會分組為相關主題。 您可能在許多不同的應用程式上看過 [檔案] 功能表。 在一般應用程式中,[檔案] 功能表項目提供儲存檔案、載入檔案及列印檔案的方法。 如果動作要顯示強制回應視窗,則標頭通常會包含省略符號,如下圖所示:

WPF 視窗,其中顯示具有省略符號的功能表項目,以指出哪個項目會顯示對話方塊。

其中兩個功能表項目具有省略符號:...。 這有助於使用者識別當使用者選取這些功能表項目時,系統會顯示強制回應視窗並暫停應用程式,直到使用者關閉該視窗為止。

此設計技術是一種簡單的方式,可讓您向使用者傳達其所預期的內容。

按鈕

您可以遵循功能表項目一節中所述的相同原則。 在按鈕文字上使用省略符號,表示當使用者按下按鈕時,就會出現強制回應對話方塊。 下圖中有兩個按鈕,很容易了解哪個按鈕會顯示對話方塊:

WPF 視窗,其中顯示具有省略符號的按鈕,以指出哪個項目會顯示對話方塊。

傳回結果

開啟另一個視窗 (特別是強制回應對話方塊) 是將狀態和資訊傳回給呼叫端程式碼的絕佳方式。

呼叫 ShowDialog() 來顯示對話方塊時,開啟對話方塊的程式碼會等到 ShowDialog 方法傳回為止。 當方法傳回時,呼叫該方法的程式碼必須決定是要繼續處理還是停止處理。 使用者通常會在對話方塊上按下 [確定] 或 [取消] 按鈕來指出這一點。

按下 [確定] 按鈕時,ShowDialog 應該設計為傳回 true,而 [取消] 按鈕則會傳回 false。 這是藉由在按下按鈕時設定 DialogResult 屬性來達成。

private void okButton_Click(object sender, RoutedEventArgs e) =>
    DialogResult = true;

private void cancelButton_Click(object sender, RoutedEventArgs e) =>
    DialogResult = false;
Private Sub okButton_Click(sender As Object, e As RoutedEventArgs)
    DialogResult = True
End Sub

Private Sub cancelButton_Click(sender As Object, e As RoutedEventArgs)
    DialogResult = False
End Sub

只有在使用 ShowDialog() 顯示對話方塊時,才能設定 DialogResult 屬性。 設定 DialogResult 屬性後,對話方塊就會關閉。

如果按鈕的 IsCancel 屬性設定為 true,並且使用 ShowDialog() 來開啟視窗,則 ESC 鍵會關閉視窗並將 DialogResult 設定為 false

如需關閉對話方塊的詳細資訊,請參閱如何關閉視窗或對話方塊

處理回應

ShowDialog() 會傳回布林值,指出使用者是接受還是取消對話方塊。 如果您要向使用者發出警示,但不需要使用者做出決策或提供資料,則可以忽略回應。 您也可以透過檢查 DialogResult 屬性來檢查回應。 下列程式碼示範如何處理回應:

var dialog = new Margins();

// Display the dialog box and read the response
bool? result = dialog.ShowDialog();

if (result == true)
{
    // User accepted the dialog box
    MessageBox.Show("Your request will be processed.");
}
else
{
    // User cancelled the dialog box
    MessageBox.Show("Sorry it didn't work out, we'll try again later.");
}
Dim marginsWindow As New Margins

Dim result As Boolean? = marginsWindow.ShowDialog()

If result = True Then
    ' User accepted the dialog box
    MessageBox.Show("Your request will be processed.")
Else
    ' User cancelled the dialog box
    MessageBox.Show("Sorry it didn't work out, we'll try again later.")
End If

marginsWindow.Show()

非強制回應對話方塊

若要顯示非強制回應對話方塊,請呼叫 Show()。 對話方塊至少應提供 [關閉] 按鈕。 還可以提供其他按鈕和互動元素來執行特定功能,例如提供 [尋找下一個] 按鈕以在文字搜尋中尋找下一個字組。

由於非強制回應對話方塊不會封鎖呼叫端程式碼繼續執行,因此您必須提供其他傳回結果的方式。 您可以執行下列其中一個步驟:

  • 在視窗上公開資料物件屬性。
  • 處理呼叫端程式碼中的 Window.Closed 事件。
  • 在視窗上建立使用者選取物件或按下特定按鈕時引發的事件。

下列範例會使用 Window.Closed 事件,在對話方塊關閉時向使用者顯示訊息方塊。 顯示的訊息會參考已關閉對話方塊的屬性。 如需關閉對話方塊的詳細資訊,請參閱如何關閉視窗或對話方塊

var marginsWindow = new Margins();

marginsWindow.Closed += (sender, eventArgs) =>
{
    MessageBox.Show($"You closed the margins window! It had the title of {marginsWindow.Title}");
};

marginsWindow.Show();
Dim marginsWindow As New Margins

AddHandler marginsWindow.Closed, Sub(sender As Object, e As EventArgs)
                                     MessageBox.Show($"You closed the margins window! It had the title of {marginsWindow.Title}")
                                 End Sub

marginsWindow.Show()

另請參閱