ダイアログ ボックスの概要 (WPF .NET)

Windows Presentation Foundation (WPF) には、独自のダイアログ ボックスを設計する方法が用意されています。 ダイアログ ボックスはウィンドウですが、特定の意図とユーザー エクスペリエンスを備えています。 この記事では、ダイアログ ボックスのしくみと、作成および使用できるダイアログ ボックスの種類について説明します。 ダイアログ ボックスの用途は次のとおりです。

  • 固有の情報をユーザーに表示する。
  • ユーザーから情報を収集する。
  • 情報の表示と収集の両方を行う。
  • オペレーティング システムのプロンプトを表示する (印刷ウィンドウなど)。
  • ファイルまたはフォルダーを選択する。

これらの種類のウィンドウは "ダイアログ ボックス" と呼ばれます。 ダイアログ ボックスは、モーダルとモードレスの 2 つの方法で表示できます。

"モーダル" ダイアログ ボックスをユーザーに表示することは、ユーザーがそのダイアログ ボックスを閉じるまで、アプリケーションで実行されていた処理を中断する手法です。 これは通常、プロンプトまたはアラートの形式になります。 そのダイアログ ボックスが閉じられるまで、アプリケーション内の他のウィンドウと対話することはできません。 "モーダル" ダイアログ ボックスが閉じられると、アプリケーションが続行されます。 最も一般的なダイアログ ボックスは、ファイルを開くかファイルを保存するプロンプトを表示するために使用され、プリンター ダイアログを表示したり、ユーザーにメッセージで何らかの状態を示したりします。

"モードレス" ダイアログ ボックスの場合、それが開いている間も、ユーザーは他のウィンドウをアクティブ化できます。 たとえば、ユーザーがドキュメント内の特定の単語の出現箇所を検索する場合を考えると、たいていはメイン ウィンドウにダイアログ ボックスが開いて、検索する単語をユーザーにたずねます。 アプリケーションでユーザーがドキュメントを編集できないようにする必要がないため、ダイアログ ボックスはモーダルである必要はありません。 モードレス ダイアログ ボックスには、少なくとも、ダイアログ ボックスを閉じるための [閉じる] ボタンが用意されています。 単語検索で次の単語を検索する [次を検索] ボタンなど、特定の機能を実行するための他のボタンが用意されていることもあります。

WPF を使用すると、メッセージ ボックス、コモン ダイアログ ボックス、カスタム ダイアログ ボックスなど、いくつかの種類のダイアログ ボックスを作成できます。 この記事では、それぞれについて説明し、対応する例として、ダイアログ ボックスのサンプルを示します。

メッセージ ボックス

"メッセージ ボックス" は、テキスト情報を表示するために使用され、ユーザーがボタンで意思決定を行うことができるダイアログ ボックスです。 次の図は、ユーザーに質問をして、質問に回答するための 3 つのボタンを表示するメッセージ ボックスを示しています。

Word processor dialog box asking if you want to save the changes to the document before the application closes.

メッセージ ボックスを作成するには、MessageBox クラスを使用します。 MessageBox を使用すると、メッセージ ボックスのテキスト、タイトル、アイコン、およびボタンを構成できます。

詳細については、「メッセージ ボックスを開く方法」を参照してください。

コモン ダイアログ ボックス

Windows では、ファイルの選択や印刷のダイアログ ボックスなど、すべてのアプリケーションに共通となるさまざまな再利用可能ダイアログ ボックスが実装されます。

そのようなダイアログ ボックスはオペレーティング システムから提供されるため、オペレーティング システム上で実行されるあらゆるアプリケーションの間で共有されます。 これらのダイアログ ボックスは使い方が一貫して同じであり、"コモン ダイアログ ボックス" と呼ばれています。 あるアプリケーションであるコモン ダイアログ ボックスを使用しているなら、他のアプリケーションでそのダイアログ ボックスの使い方を覚える必要がありません。

WPF によって、ファイルを開く、ファイルを保存する、フォルダーを開く、印刷するための共通のダイアログ ボックスはカプセル化され、使用できるマネージド クラスとして公開されています。

Open file dialog box called from WPF.

コモン ダイアログ ボックスの詳細については、次の記事を参照してください。

カスタム ダイアログ ボックス

コモン ダイアログ ボックスは便利であり、可能なときには使用する必要がありますが、ドメイン固有のダイアログ ボックスの要件はサポートされていません。 このような場合は、独自のダイアログ ボックスを作成する必要があります。 これから説明するように、ダイアログ ボックスは、特殊な動作を持つウィンドウです。 それらの動作は Window で実装され、このウィンドウを使用して、カスタムのモーダルおよびモードレス ダイアログ ボックスを作成します。

独自のダイアログ ボックスを作成する際には、さまざまな設計上の考慮事項について考える必要があります。 アプリケーション ウィンドウとダイアログ ボックスの両方に類似点 (同じ基本クラスの共有など) が含まれていますが、ダイアログ ボックスは特定の目的のために使用されます。 通常、ユーザーに何らかの情報や応答を求めるメッセージを表示する必要がある場合は、ダイアログ ボックスが必要とされます。 一般的に、ダイアログ ボックス (モーダル) が表示されている間はアプリケーションが一時停止し、アプリケーションの残りの部分へのアクセスが制限されます。 ダイアログ ボックスが閉じられると、アプリケーションは続行されます。 ただし、対話をダイアログ ボックスだけに限ることは、要件ではありません。

WPF ウィンドウを閉じると、もう一度開くことはできません。 カスタム ダイアログ ボックスは WPF ウィンドウであり、同じ規則が適用されます。 ウィンドウを閉じる方法については、「ウィンドウまたはダイアログ ボックスを閉じる方法」を参照してください。

ダイアログ ボックスの実装

ダイアログ ボックスを設計するときは、適切なユーザー エクスペリエンスを作成するための次の推奨事項に従います。

❌ ダイアログ ウィンドウを煩雑にしないでください。 ダイアログ エクスペリエンスは、ユーザーがデータを入力したり、選択を行ったりできるようにするためのものです。

✔️ ウィンドウを閉じるための [OK] ボタンを用意します。

✔️ [OK] ボタンの IsDefault プロパティを true に設定して、ユーザーが Enter キーを押すことでウィンドウを受け入れて閉じることができるようにします。

✔️ ユーザーがウィンドウを閉じ、続行を希望しないことを示すことができるように、 [キャンセル] ボタンを追加することを検討してください。

✔️ [キャンセル] ボタンの IsCancel プロパティを true に設定して、ユーザーが Esc キーを押してウィンドウを閉じることができるようにします。

✔️ ダイアログが何を表しているか、またはダイアログを使用してユーザーが何を行う必要があるのかを正確に表すように、ウィンドウのタイトルを設定します。

✔️ ユーザーがウィンドウのサイズを小さくしすぎないように、ウィンドウの幅と高さの最小値を設定します。

✔️ ShowInTaskbarfalse に設定されている場合は、ウィンドウのサイズ変更機能を無効にすることを検討してください。 ResizeModeNoResize に設定して、サイズ変更を無効にすることもできます。

次のコードは、この構成の例を示しています。

<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 から次の図のようなウィンドウが作成されます。

A dialog box window for WPF that shows left, top, right, bottom text boxes.

ダイアログ ボックスを開く UI 要素

ダイアログ ボックスのユーザー エクスペリエンスは、それを開くウィンドウのメニュー バーまたはボタンにも及びます。 メニュー項目またはボタンで実行される機能で、機能を続行する前にダイアログ ボックスでユーザーの操作が必要な場合、コントロールの見出しテキストの終わりに省略記号を使用する必要があります。

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

メニュー項目またはボタンで実行する機能で、ユーザーの操作を必要としないダイアログ ボックス ( [バージョン情報] ダイアログ ボックスなど) が表示される場合、省略記号は必要ありません。

メニュー項目は、関連したテーマにグループ化されたアプリケーションのアクションをユーザーに提供するための一般的な方法です。 多くの異なるアプリケーションで [ファイル] メニューを見たことがあるでしょう。 一般的なアプリケーションの場合、 [ファイル] メニュー項目を使用して、ファイルの保存、ファイルの読み込み、ファイルの印刷を行うことができます。 アクションでモーダル ウィンドウが表示される場合、次の図に示すように通常はヘッダーに省略記号が含まれています。

A WPF window that shows menu items with an ellipsis to indicate which item shows a dialog box.

2 つのメニュー項目に省略記号 (...) が表示されています。 これにより、ユーザーは、それらのメニュー項目を選択するとモーダル ウィンドウが表示され、それをユーザーが閉じるまでアプリケーションが一時停止することを識別しやすくなります。

この設計手法は、ユーザーに予期されることをユーザーに通知するための簡単な方法です。

ボタン

メニュー項目」セクションで説明したのと同じ原則に従うことができます。 ユーザーがボタンを押すとモーダル ダイアログが表示されることを示すために、ボタンのテキストに省略記号を使用します。 次の図には 2 つのボタンがあり、どのボタンでダイアログ ボックスが表示されるかを簡単に理解できます。

A WPF window that shows buttons with an ellipsis to indicate which item shows a dialog box.

結果を返す

別のウィンドウ (特にモーダル ダイアログ ボックス) を開くことは、呼び出し元のコードに状態と情報を返すための優れた方法です。

ShowDialog() を呼び出すことによってダイアログ ボックスが表示される場合、ダイアログ ボックスを開いたコードは、ShowDialog メソッドが戻るまで待機します。 メソッドが戻ると、それを呼び出したコードは、処理を続行するか、それとも処理を停止するかを決定する必要があります。 ユーザーは、通常、ダイアログ ボックスの [OK] または [キャンセル] ボタンを押してこれを示します。

ShowDialog は、 [OK] ボタンが押されたときは 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

DialogResult プロパティは、ダイアログ ボックスが ShowDialog() を使用して表示された場合にのみ設定できます。 DialogResult プロパティが設定されると、ダイアログ ボックスが閉じます。

ボタンの IsCancel プロパティが true に設定され、ウィンドウが ShowDialog() で開かれている場合、Esc キーでウィンドウを閉じ、DialogResultfalse に設定します。

ダイアログ ボックスを閉じる方法の詳細については、「ウィンドウまたはダイアログ ボックスを閉じる方法」を参照してください。

応答の処理

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

関連項目