ダイアログ ボックスの概要

スタンドアロン アプリケーションには、通常、メイン ウィンドウがあり、そこには、アプリケーションが操作する主なデータが表示され、そのデータをメニュー バー、ツール バー、ステータス バーなどのユーザー インターフェイス (UI) メカニズムを通じて処理する機能が公開されます。 重要なアプリケーションは、次のようなことをするための追加のウィンドウを表示することもあります。

  • 固有の情報をユーザーに表示する。

  • ユーザーから情報を収集する。

  • 情報の表示と収集の両方を行う。

これらの種類のウィンドウは "ダイアログ ボックス" と呼ばれ、モーダルとモードレスの 2 種類があります。

"モーダル" ダイアログ ボックスは、機能が続行するにはユーザーからの追加データが必要なときに、機能によって表示されます。 機能は、モーダル ダイアログ ボックスに依存してデータを収集するため、モーダル ダイアログ ボックスが開いている間、ユーザーはアプリケーション内の他のウィンドウをアクティブ化することはできません。 ほとんどの場合、ユーザーは [OK] または [キャンセル] ボタンを押すことによって、モーダル ダイアログ ボックスの操作を終了したことをモーダル ダイアログ ボックスに知らせることができます。 [OK] ボタンを押すことは、ユーザーがデータを入力し、そのデータの処理を続行することを機能に求めていることを示します。 [キャンセル] ボタンを押すことは、ユーザーが機能の実行を停止することを求めていることを示します。 モーダル ダイアログ ボックスの最も一般的な例は、データを開く、保存する、および印刷するために表示されます。

一方、"モードレス" ダイアログ ボックスは、それが開いている間も、ユーザーは他のウィンドウをアクティブ化できます。 たとえば、ユーザーがドキュメント内の特定の単語の出現箇所を検索する場合、メイン ウィンドウは、多くの場合、ダイアログ ボックスを開いて、検索する単語をユーザーに尋ねます。 しかし、単語の検索中もユーザーはドキュメントを編集できるため、ダイアログ ボックスがモーダルである必要はありません。 モードレス ダイアログ ボックスには、少なくとも、ダイアログ ボックスを閉じる [閉じる] ボタンがあり、単語検索の検索条件に一致する次の単語を検索するための [次を検索] ボタンなど、特定の機能を実行するための追加のボタンが表示されることもあります。

Windows Presentation Foundation (WPF) では、メッセージ ボックス、コモン ダイアログ ボックス、カスタム ダイアログ ボックスなど、いくつかの種類のダイアログ ボックスを作成できます。 このトピックでは、それぞれについて説明し、該当する例として、ダイアログ ボックスのサンプルを示します。

メッセージ ボックス

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

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

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

// Configure the message box to be displayed
string messageBoxText = "Do you want to save changes?";
string caption = "Word Processor";
MessageBoxButton button = MessageBoxButton.YesNoCancel;
MessageBoxImage icon = MessageBoxImage.Warning;
' Configure the message box to be displayed
Dim messageBoxText As String = "Do you want to save changes?"
Dim caption As String = "Word Processor"
Dim button As MessageBoxButton = MessageBoxButton.YesNoCancel
Dim icon As MessageBoxImage = MessageBoxImage.Warning

メッセージ ボックスを表示するには、次のコードに示されているように、staticShow メソッドを呼び出します。

// Display message box
MessageBox.Show(messageBoxText, caption, button, icon);
' Display message box
MessageBox.Show(messageBoxText, caption, button, icon)

メッセージ ボックスを表示するコードで、ユーザーの決定 (どのボタンが押されたか) を検出して処理する必要があるときには、コードは、次のコードに示されているように、メッセージ ボックスの結果を検査できます。

// Display message box
MessageBoxResult result = MessageBox.Show(messageBoxText, caption, button, icon);

// Process message box results
switch (result)
{
    case MessageBoxResult.Yes:
        // User pressed Yes button
        // ...
        break;
    case MessageBoxResult.No:
        // User pressed No button
        // ...
        break;
    case MessageBoxResult.Cancel:
        // User pressed Cancel button
        // ...
        break;
}
' Display message box
Dim result As MessageBoxResult = MessageBox.Show(messageBoxText, caption, button, icon)

' Process message box results
Select Case result
    Case MessageBoxResult.Yes
        ' User pressed Yes button
        ' ...
    Case MessageBoxResult.No
        ' User pressed No button
        ' ...
    Case MessageBoxResult.Cancel
        ' User pressed Cancel button
        ' ...
End Select

メッセージ ボックスの使用の詳細については、MessageBox、「メッセージ ボックスのサンプル」、および「ダイアログ ボックスのサンプル」を参照してください。

MessageBox では単純なダイアログ ボックス ユーザー エクスペリエンスを提供できますが、MessageBox を使用する利点は XAML ブラウザー アプリケーション (XBAP) など、部分信頼セキュリティ サンドボックス (「セキュリティ」を参照) 内で実行するアプリケーションによって表示できる唯一の種類のウィンドウであることです。

ほとんどのダイアログ ボックスは、テキスト、選択 (チェック ボックス)、相互に排他的な選択 (オプション ボタン)、リスト選択 (リスト ボックス、コンボ ボックス、ドロップダウン リスト ボックス) など、メッセージ ボックスの結果よりも複雑なデータを表示し、収集します。 これらのために、Windows Presentation Foundation (WPF) には、いくつかのコモン ダイアログ ボックスが用意されていて、ユーザー独自のダイアログ ボックスを作成することもできますが、どちらの使用も、完全な信頼で実行しているアプリケーションに限られます。

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

Windows では、ファイルを開く、ファイルを保存する、印刷するためのダイアログ ボックスなど、すべてのアプリケーションに共通の、さまざまな再利用可能なダイアログ ボックスが実装されます。 これらのダイアログ ボックスはオペレーティング システムによって実装されるため、そのオペレーティング システム上で実行するすべてのアプリケーション間で共有でき、ユーザー エクスペリエンスの一貫性を保つことができます。ユーザーが 1 つのアプリケーションで、オペレーティング システムによって提供されるダイアログ ボックスの使用に慣れると、他のアプリケーションでも、そのダイアログ ボックスの使用法を学ぶ必要はありません。 これらのダイアログ ボックスはすべてのアプリケーションで使用でき、一貫したユーザー エクスペリエンスの提供に役立つため、"コモン ダイアログ ボックス" と呼ばれます。

Windows Presentation Foundation (WPF) では、ファイルを開く、ファイルを保存する、および印刷コモン ダイアログ ボックスがカプセル化され、スタンドアロン アプリケーション内で使用できるマネージド クラスとして公開されます。 このトピックでは、それぞれの概要を簡単に説明します。

[ファイルを開く] ダイアログ

[ファイルを開く] ダイアログ ボックスは、次の図に示されているように、開くファイルの名前を取得するために、ファイルを開く機能によって使用されます。

An Open dialog box showing the location to retrieve the file.

[ファイルを開く] コモン ダイアログ ボックスは、OpenFileDialog クラスとして実装され、Microsoft.Win32 名前空間にあります。 次のコードは、[ファイルを開く] ダイアログ ボックスの作成、構成、および表示の方法と、結果を処理する方法を示しています。

// Configure open file dialog box
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".txt"; // Default file extension
dlg.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension

// Show open file dialog box
Nullable<bool> result = dlg.ShowDialog();

// Process open file dialog box results
if (result == true)
{
    // Open document
    string filename = dlg.FileName;
}
' Configure open file dialog box
Dim dlg As New Microsoft.Win32.OpenFileDialog()
dlg.FileName = "Document" ' Default file name
dlg.DefaultExt = ".txt" ' Default file extension
dlg.Filter = "Text documents (.txt)|*.txt" ' Filter files by extension

' Show open file dialog box
Dim result? As Boolean = dlg.ShowDialog()

' Process open file dialog box results
If result = True Then
    ' Open document
    Dim filename As String = dlg.FileName
End If

ファイルを開くダイアログ ボックスの詳細については、「Microsoft.Win32.OpenFileDialog」を参照してください。

注意

OpenFileDialog を使用すると、部分信頼で実行しているアプリケーションがファイル名を安全に取得できます (「セキュリティ」を参照)。

[ファイルの保存] ダイアログ ボックス

[ファイルの保存] ダイアログ ボックスは、次の図に示されているように、保存するファイルの名前を取得するために、ファイルを保存する機能によって使用されます。

A Save As dialog box showing the location to save the file.

[ファイルの保存] コモン ダイアログ ボックスは、SaveFileDialog クラスとして実装され、Microsoft.Win32 名前空間にあります。 次のコードは、[ファイルを開く] ダイアログ ボックスの作成、構成、および表示の方法と、結果を処理する方法を示しています。

// Configure save file dialog box
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".txt"; // Default file extension
dlg.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension

// Show save file dialog box
Nullable<bool> result = dlg.ShowDialog();

// Process save file dialog box results
if (result == true)
{
    // Save document
    string filename = dlg.FileName;
}
' Configure save file dialog box
Dim dlg As New Microsoft.Win32.SaveFileDialog()
dlg.FileName = "Document" ' Default file name
dlg.DefaultExt = ".txt" ' Default file extension
dlg.Filter = "Text documents (.txt)|*.txt" ' Filter files by extension

' Show save file dialog box
Dim result? As Boolean = dlg.ShowDialog()

' Process save file dialog box results
If result = True Then
    ' Save document
    Dim filename As String = dlg.FileName
End If

[ファイルの保存] ダイアログ ボックスの詳細については、「Microsoft.Win32.SaveFileDialog」を参照してください。

次の図に示されているように、[印刷] ダイアログ ボックスは、ユーザーがデータを印刷するプリンターを選択し、構成するために、印刷機能によって使用されます。

Screenshot that shows a Print dialog box.

[印刷] コモン ダイアログ ボックスは、PrintDialog クラスとして実装され、System.Windows.Controls 名前空間にあります。 次のコードは、[印刷] ダイアログ ボックスの作成、構成、および表示の方法を示しています。

// Configure printer dialog box
System.Windows.Controls.PrintDialog dlg = new System.Windows.Controls.PrintDialog();
dlg.PageRangeSelection = PageRangeSelection.AllPages;
dlg.UserPageRangeEnabled = true;

// Show save file dialog box
Nullable<bool> result = dlg.ShowDialog();

// Process save file dialog box results
if (result == true)
{
    // Print document
}
' Configure printer dialog box
Dim dlg As New PrintDialog()
dlg.PageRangeSelection = PageRangeSelection.AllPages
dlg.UserPageRangeEnabled = True

' Show save file dialog box
Dim result? As Boolean = dlg.ShowDialog()

' Process save file dialog box results
If result = True Then
    ' Print document
End If

[印刷] ダイアログ ボックスの詳細については、「System.Windows.Controls.PrintDialog」を参照してください。 WPF での印刷の詳細については、「印刷の概要」を参照してください。

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

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

モーダルのカスタム ダイアログ ボックスの作成

このトピックでは、Window を使用して一般的なモーダル ダイアログ ボックス実装を作成する方法を示し、Margins ダイアログ ボックスを例として使用します (「ダイアログ ボックスのサンプル」を参照)。 Margins ダイアログ ボックスを次の図に示します。

A Margins dialog box with fields to define left margin, top margin, right margin, and bottom margin.

モーダル ダイアログ ボックスの構成

一般的なダイアログ ボックスのユーザー インターフェイスには、次の項目が含まれます。

  • 必要なデータを収集するために必要なさまざまなコントロール。

  • ユーザーがクリックすると、ダイアログ ボックスを閉じ、機能に戻り、処理を続行する [OK] ボタン。

  • ユーザーがクリックすると、ダイアログ ボックスを閉じ、機能が処理を続行するのを停止する [キャンセル] ボタン。

  • タイトル バーの [閉じる] ボタン。

  • アイコン。

  • 最小化ボタン、最大化ボタン、および元に戻すボタン。

  • ダイアログ ボックスを最小化、最大化、元に戻す、および閉じるための [システム] メニュー。

  • ダイアログ ボックスを開いたウィンドウの中央上の位置。

  • 可能な場合は、ダイアログ ボックスが小さすぎないようにサイズを変更し、ユーザーに便利な既定サイズを提供する機能。 これには、既定のディメンションと最小ディメンションの両方を設定する必要があります。

  • [キャンセル] ボタンを押すことと同じ効果を持つキーボード ショートカットとしての ESC キー。 これを行うには、 [キャンセル] ボタンの IsCancel プロパティを true に設定します。

  • [OK] ボタンを押すことと同じ効果を持つキーボード ショートカットとしての ENTER (または RETURN) キー。 これを行うには、 [OK] ボタンの IsDefault プロパティを true に設定します。

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

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.MarginsDialogBox"
    xmlns:local="clr-namespace:SDKSample"
    Title="Margins"
    Height="190"
    Width="300"
    MinHeight="10"
    MinWidth="300"
    ResizeMode="CanResizeWithGrip"
    ShowInTaskbar="False"
    WindowStartupLocation="CenterOwner" 
    FocusManager.FocusedElement="{Binding ElementName=leftMarginTextBox}">

  <Grid>
    <!-- Accept or Cancel -->
    <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="4">
      <Button Name="okButton" Click="okButton_Click" IsDefault="True">OK</Button>
      <Button Name="cancelButton" IsCancel="True">Cancel</Button>
    </StackPanel>
  </Grid >
</Window>
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace SDKSample
{
    public partial class MarginsDialogBox : Window
    {
        public MarginsDialogBox()
        {
            InitializeComponent();
        }
    }
}
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input

Namespace SDKSample
    Public Class MarginsDialogBox
        Inherits Window

        Public Sub New()
            Me.InitializeComponent()
        End Sub
    End Class
End Namespace

ダイアログ ボックスのユーザー エクスペリエンスは、ダイアログ ボックスを開くウィンドウのメニュー バーにも及びます。 メニュー項目が、機能の続行には、ダイアログ ボックスでのユーザーの操作を必要とする機能を実行するときには、次に示されているように、その機能のメニュー項目の見出しに省略記号を付けます。

<!--Main Window-->
<MenuItem Name="formatMarginsMenuItem" Header="_Margins..." Click="formatMarginsMenuItem_Click" />

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

モーダル ダイアログ ボックスを開く

ダイアログ ボックスは、通常、ワード プロセッサでドキュメントの余白を設定するなど、ドメイン固有の機能を実行するためにユーザーがメニュー項目を選択した結果として表示されます。 ウィンドウをダイアログ ボックスとして表示するのは、通常のウィンドウを表示するのと同様ですが、ダイアログ ボックス固有の追加の構成が必要です。 ダイアログ ボックスのインスタンス化、構成、および開くプロセスの全体を、次のコードに示します。

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;

namespace SDKSample
{
    public partial class MainWindow : Window
    {
        bool needsToBeSaved;
        void formatMarginsMenuItem_Click(object sender, RoutedEventArgs e)
        {
            // Instantiate the dialog box
            MarginsDialogBox dlg = new MarginsDialogBox();

            // Configure the dialog box
            dlg.Owner = this;
            dlg.DocumentMargin = this.documentTextBox.Margin;

            // Open the dialog box modally
            dlg.ShowDialog();
        }
    }
}
Imports System.ComponentModel
Imports System.Windows
Imports System.Windows.Controls
Imports Microsoft.Win32

Namespace SDKSample
    Public Class MainWindow
        Inherits Window
        
        Private Sub formatMarginsMenuItem_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Instantiate the dialog box
            Dim dlg As New MarginsDialogBox

            ' Configure the dialog box
            dlg.Owner = Me
            dlg.DocumentMargin = Me.documentTextBox.Margin

            ' Open the dialog box modally 
            dlg.ShowDialog()
        End Sub
    End Class
End Namespace

ここでは、コードは、既定の情報 (現在の余白) をダイアログ ボックスに渡しています。 また、Window.Owner プロパティに、ダイアログ ボックスを表示しているウィンドウへの参照を設定します。 一般には、常にダイアログ ボックスの所有者を設定して、すべてのダイアログ ボックスに共通のウィンドウ状態に関連する動作を提供する必要があります (詳細については、「WPF ウィンドウの概要」を参照してください)。

注意

ダイアログ ボックスのユーザー インターフェイス (UI) オートメーションを所有者に提供する必要があります (「UI オートメーションの概要」を参照)。

構成されたダイアログ ボックスは、ShowDialog メソッドを呼び出すことによって、モーダルとして表示されます。

ユーザー指定データの検証

ダイアログ ボックスが開かれ、ユーザーが必要なデータを指定すると、ダイアログ ボックスは、指定されたデータが有効であることを確認する必要があります。これは、次のような理由からです。

  • セキュリティの観点から、すべての入力を検証する必要があります。

  • ドメイン固有の観点から、データの検証は、誤ったデータがコードによって処理されて、例外がスローされるのを防ぎます。

  • ユーザー エクスペリエンスの観点から、ダイアログ ボックスは、入力したデータが無効であることを示すことによって、ユーザーを支援できます。

  • パフォーマンスの観点から、多層アプリケーションでのデータの検証は、特に、アプリケーションが Web サービスまたはサーバーベースのデータベースで構成される場合、クライアント層とアプリケーション層の間のラウンド トリップの回数を減らすことができます。

WPF 内でバインド コントロールを検証するには、検証規則を定義して、バインドに関連付ける必要があります。 検証規則は、ValidationRule から派生するカスタム クラスです。 次の例は、バインドされた値が Double であり、指定された範囲内にあることを確認する検証規則 MarginValidationRule を示しています。

using System.Globalization;
using System.Windows.Controls;

namespace SDKSample
{
    public class MarginValidationRule : ValidationRule
    {
        double minMargin;
        double maxMargin;

        public double MinMargin
        {
            get { return this.minMargin; }
            set { this.minMargin = value; }
        }

        public double MaxMargin
        {
            get { return this.maxMargin; }
            set { this.maxMargin = value; }
        }

        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            double margin;

            // Is a number?
            if (!double.TryParse((string)value, out margin))
            {
                return new ValidationResult(false, "Not a number.");
            }

            // Is in range?
            if ((margin < this.minMargin) || (margin > this.maxMargin))
            {
                string msg = string.Format("Margin must be between {0} and {1}.", this.minMargin, this.maxMargin);
                return new ValidationResult(false, msg);
            }

            // Number is valid
            return new ValidationResult(true, null);
        }
    }
}
Imports System.Globalization
Imports System.Windows.Controls

Namespace SDKSample
    Public Class MarginValidationRule
        Inherits ValidationRule

        Private _maxMargin As Double
        Private _minMargin As Double

        Public Property MaxMargin() As Double
            Get
                Return Me._maxMargin
            End Get
            Set(ByVal value As Double)
                Me._maxMargin = value
            End Set
        End Property

        Public Property MinMargin() As Double
            Get
                Return Me._minMargin
            End Get
            Set(ByVal value As Double)
                Me._minMargin = value
            End Set
        End Property

        Public Overrides Function Validate(ByVal value As Object, ByVal cultureInfo As CultureInfo) As ValidationResult
            Dim margin As Double

            ' Is a number?
            If Not Double.TryParse(CStr(value), margin) Then
                Return New ValidationResult(False, "Not a number.")
            End If

            ' Is in range?
            If ((margin < Me.MinMargin) OrElse (margin > Me.MaxMargin)) Then
                Dim msg As String = String.Format("Margin must be between {0} and {1}.", Me.MinMargin, Me.MaxMargin)
                Return New ValidationResult(False, msg)
            End If

            ' Number is valid
            Return New ValidationResult(True, Nothing)
        End Function
    End Class
End Namespace

このコードでは、データを検証して適切な ValidationResult を返す Validate メソッドをオーバーライドすることによって、検証規則の検証ロジックを実装しています。

検証規則をバインド コントロールに関連付けるには、次のマークアップを使用します。

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.MarginsDialogBox"
    xmlns:local="clr-namespace:SDKSample"
    Title="Margins"
    Height="190"
    Width="300"
    MinHeight="10"
    MinWidth="300"
    ResizeMode="CanResizeWithGrip"
    ShowInTaskbar="False"
    WindowStartupLocation="CenterOwner" 
    FocusManager.FocusedElement="{Binding ElementName=leftMarginTextBox}">

  <Grid>

    <!-- Left Margin -->
    <Label Grid.Column="0" Grid.Row="0">Left Margin:</Label>
    <TextBox Name="leftMarginTextBox" Grid.Column="1" Grid.Row="0">
      <TextBox.Text>
        <Binding Path="Left" UpdateSourceTrigger="PropertyChanged">
          <Binding.ValidationRules>
            <local:MarginValidationRule MinMargin="0" MaxMargin="10" />
          </Binding.ValidationRules>
        </Binding>
      </TextBox.Text>
    </TextBox>
  </Grid >
</Window>

検証規則が関連付けられた後、データがバインド コントロールに入力されると、WPF によって検証規則が自動的に適用されます。 コントロールに無効なデータが含まれているときには、次の図に示されているように、無効なコントロールの周囲に赤い境界線が WPF によって表示されます。

A Margins dialog box with a red border around the invalid left margin value.

WPF では、ユーザーが有効なデータを入力するまで、ユーザーが無効なコントロールに制限されるわけではありません。 これは、ダイアログ ボックスとして適切な動作です。データが有効かどうかにかかわらず、ユーザーはダイアログ ボックス内のコントロールを自由に移動できる必要があります。 ただしこれは、ユーザーが無効なデータを入力して、 [OK] ボタンをクリックできることを意味します。 このため、 [OK] ボタンが押されたときには、コードも Click イベントを処理することによって、ダイアログ ボックス内のすべてのコントロールを検証する必要はあります。

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace SDKSample
{
    public partial class MarginsDialogBox : Window
    {
        void okButton_Click(object sender, RoutedEventArgs e)
        {
            // Don't accept the dialog box if there is invalid data
            if (!IsValid(this)) return;
        }

        // Validate all dependency objects in a window
        bool IsValid(DependencyObject node)
        {
            // Check if dependency object was passed
            if (node != null)
            {
                // Check if dependency object is valid.
                // NOTE: Validation.GetHasError works for controls that have validation rules attached
                bool isValid = !Validation.GetHasError(node);
                if (!isValid)
                {
                    // If the dependency object is invalid, and it can receive the focus,
                    // set the focus
                    if (node is IInputElement) Keyboard.Focus((IInputElement)node);
                    return false;
                }
            }

            // If this dependency object is valid, check all child dependency objects
            foreach (object subnode in LogicalTreeHelper.GetChildren(node))
            {
                if (subnode is DependencyObject)
                {
                    // If a child dependency object is invalid, return false immediately,
                    // otherwise keep checking
                    if (IsValid((DependencyObject)subnode) == false) return false;
                }
            }

            // All dependency objects are valid
            return true;
        }
    }
}
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input

Namespace SDKSample
    Public Class MarginsDialogBox
        Inherits Window

        Private Sub okButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Don't accept the dialog box if there is invalid data
            If Not Me.IsValid(Me) Then Return
        End Sub

        ' Validate all dependency objects in a window
        Private Function IsValid(ByVal node As DependencyObject) As Boolean
            ' Check if dependency object was passed and if dependency object is valid.
            ' NOTE: Validation.GetHasError works for controls that have validation rules attached 
            If ((Not node Is Nothing) AndAlso Validation.GetHasError(node)) Then
                ' If the dependency object is invalid, and it can receive the focus,
                ' set the focus
                If TypeOf node Is IInputElement Then
                    Keyboard.Focus(DirectCast(node, IInputElement))
                End If
                Return False
            End If

            ' If this dependency object is valid, check all child dependency objects
            Dim subnode As Object
            For Each subnode In LogicalTreeHelper.GetChildren(node)
                If (TypeOf subnode Is DependencyObject AndAlso Not Me.IsValid(DirectCast(subnode, DependencyObject))) Then
                    ' If a child dependency object is invalid, return false immediately,
                    ' otherwise keep checking
                    Return False
                End If
            Next

            ' All dependency objects are valid
            Return True
        End Function
    End Class
End Namespace

このコードでは、ウィンドウ上のすべての依存関係オブジェクトが列挙されます。いずれかが無効な場合 (GetHasError によって返される) は、無効なコントロールがフォーカスを取得し、IsValid メソッドでは false が返され、ウィンドウは無効とみなされます。

ダイアログ ボックスが有効な場合は、安全に閉じて、戻ることができます。 復帰プロセスの一環として、呼び出し元の機能に結果を返す必要があります。

モーダル ダイアログの結果を設定する

ShowDialog を使用してダイアログ ボックスを開くことは、基本的にメソッドの呼び出しと似ています。ShowDialog を使用してダイアログ ボックスを開いたコードは、ShowDialog が戻るまで待機します。 ShowDialog が戻ると、それを呼び出したコードは、ユーザーが [OK] ボタンを押したか、それとも [キャンセル] ボタンを押したかに基づいて、処理を続行するか、それとも処理を停止するかを決定する必要があります。 この決定を容易にするために、ダイアログ ボックスは、ユーザーの選択を ShowDialog メソッドから返された Boolean 値として返す必要があります。

[OK] ボタンがクリックされたときに、ShowDialog では true を返す必要があります。 このためには、 [OK] ボタンがクリックされたときに、ダイアログ ボックスの DialogResult プロパティを設定します。

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace SDKSample
{
    public partial class MarginsDialogBox : Window
    {

        void okButton_Click(object sender, RoutedEventArgs e)
        {
            this.DialogResult = true;
        }
    }
}
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input

Namespace SDKSample
    Public Class MarginsDialogBox
        Inherits Window

        Private Sub okButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Dialog box accepted
            MyBase.DialogResult = New Nullable(Of Boolean)(True)
        End Sub
    End Class
End Namespace

DialogResult プロパティを設定すると、ウィンドウも自動的に閉じられるため、Close を明示的に呼び出す必要がなくなることに注意してください。

[キャンセル] ボタンがクリックされたときには、ShowDialogfalse を返す必要があり、DialogResult プロパティを設定する必要もあります。

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace SDKSample
{
    public partial class MarginsDialogBox : Window
    {

        void cancelButton_Click(object sender, RoutedEventArgs e)
        {
            // Dialog box canceled
            this.DialogResult = false;
        }
    }
}
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input

Namespace SDKSample
    Public Class MarginsDialogBox
        Inherits Window

        Private Sub cancelButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Dialog box canceled
            Me.DialogResult = False
        End Sub
    End Class
End Namespace

ボタンの IsCancel プロパティが true に設定され、ユーザーが [キャンセル] ボタンか Esc キーを押すと、DialogResult は自動的に false に設定されます。 次のマークアップは、前のコードと同じ効果を持ち、Click イベントを処理する必要はありません。

<Button Name="cancelButton" IsCancel="True">Cancel</Button>

ユーザーがタイトル バーの [閉じる] ボタンを押すか、 [システム] メニューの [閉じる] メニュー項目を選ぶと、ダイアログ ボックスによって自動的に false が返されます。

モーダル ダイアログ ボックスから返されたデータの処理

DialogResult がダイアログ ボックスによって設定されると、ダイアログ ボックスを開いた機能は、ShowDialog が戻ったときに、DialogResult プロパティを検査することによって、ダイアログ ボックスの結果を取得することができます。

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;

namespace SDKSample
{
    public partial class MainWindow : Window
    {

        void formatMarginsMenuItem_Click(object sender, RoutedEventArgs e)
        {

            // Process data entered by user if dialog box is accepted
            if (dlg.DialogResult == true)
            {
                // Update fonts
                this.documentTextBox.Margin = dlg.DocumentMargin;
            }
        }
    }
}
Imports System.ComponentModel
Imports System.Windows
Imports System.Windows.Controls
Imports Microsoft.Win32

Namespace SDKSample
    Public Class MainWindow
        Inherits Window
        
        Private Sub formatMarginsMenuItem_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            ' Process data entered by user if dialog box is accepted
            If (dlg.DialogResult.GetValueOrDefault = True) Then
                Me.documentTextBox.Margin = dlg.DocumentMargin
            End If
        End Sub
    End Class
End Namespace

ダイアログの結果が true の場合、機能ではそれをキューとして使用して、ユーザーによって指定されたデータを取得し、処理します。

注意

ShowDialog が戻った後、ダイアログ ボックスを再び開くことはできません。 代わりに、新しいインスタンスを作成する必要があります。

ダイアログの結果が false の場合、機能では処理を適切に終了する必要があります。

モードレス カスタム ダイアログ ボックスの作成

次の図に示されている [検索] ダイアログ ボックスなどのモードレス ダイアログ ボックスは、基本的な外観はモーダル ダイアログ ボックスと同じです。

Screenshot that shows a Find dialog box.

しかし、次のセクションで説明するように、動作は少し異なります。

モードレス ダイアログ ボックスを開く

モードレス ダイアログ ボックスは、Show メソッドを呼び出すことによって開かれます。

<!--Main Window-->
<MenuItem Name="editFindMenuItem" Header="_Find" InputGestureText="Ctrl+F" Click="editFindMenuItem_Click" />
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;

namespace SDKSample
{
    public partial class MainWindow : Window
    {
        void editFindMenuItem_Click(object sender, RoutedEventArgs e)
        {
            // Instantiate the dialog box
            FindDialogBox dlg = new FindDialogBox(this.documentTextBox);

            // Configure the dialog box
            dlg.Owner = this;
            dlg.TextFound += new TextFoundEventHandler(dlg_TextFound);

            // Open the dialog box modally
            dlg.Show();
        }
    }
}
Imports System.ComponentModel
Imports System.Windows
Imports System.Windows.Controls
Imports Microsoft.Win32

Namespace SDKSample
    Public Class MainWindow
        Inherits Window
        
        Private Sub editFindMenuItem_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            Dim dlg As New FindDialogBox(Me.documentTextBox)
            dlg.Owner = Me
            AddHandler dlg.TextFound, New TextFoundEventHandler(AddressOf Me.dlg_TextFound)
            dlg.Show()
        End Sub
    End Class
End Namespace

ShowDialog とは異なり、Show は直ちに戻ります。 その結果、呼び出し元のウィンドウは、モードレス ダイアログ ボックスが閉じられたことを知ることができず、したがって、ダイアログ ボックスの結果を確認するタイミングを判断したり、ダイアログ ボックスからデータを取得して、さらに処理したりすることができません。 代わりに、ダイアログ ボックスは、別の方法を作成して、呼び出し元のウィンドウに処理用のデータを返す必要があります。

モードレス ダイアログ ボックスから返されたデータの処理

この例では、FindDialogBox によって、検索対象のテキストに応じて、特定の頻度ではなく、1 つ以上の検索結果がメイン ウィンドウに返されます。 モーダル ダイアログ ボックスと同様、モードレス ダイアログ ボックスは、プロパティを使用して結果を返すことができます。 ただし、ダイアログ ボックスを所有しているウィンドウは、それらのプロパティを確認するタイミングを知る必要があります。 これを可能にする方法の 1 つは、ダイアログ ボックスで、テキストが見つかったときに発生するイベントを実装することです。 FindDialogBox は、この目的で TextFoundEvent を実装し、最初にデリゲートを必要とします。

using System;

namespace SDKSample
{
    public delegate void TextFoundEventHandler(object sender, EventArgs e);
}
Namespace SDKSample
   Public Delegate Sub TextFoundEventHandler(ByVal sender As Object, ByVal e As EventArgs)
End Namespace

TextFoundEventHandler デリゲートを使用して、FindDialogBox では TextFoundEvent が実装されます。

using System;
using System.Windows;
using System.Windows.Controls;
using System.Text.RegularExpressions;

namespace SDKSample
{
    public partial class FindDialogBox : Window
    {
        public event TextFoundEventHandler TextFound;

        protected virtual void OnTextFound()
        {
            TextFoundEventHandler textFound = this.TextFound;
            if (textFound != null) textFound(this, EventArgs.Empty);
        }

    }
}
Imports System.Windows
Imports System.Windows.Controls
Imports System.Text.RegularExpressions

Namespace SDKSample

    Public Class FindDialogBox
        Inherits Window

        Public Event TextFound As TextFoundEventHandler

        Protected Overridable Sub OnTextFound()
            RaiseEvent TextFound(Me, EventArgs.Empty)
        End Sub

    End Class
End Namespace

その結果、Find では、検索結果が見つかった場合にイベントを発生させることができます。

using System;
using System.Windows;
using System.Windows.Controls;
using System.Text.RegularExpressions;

namespace SDKSample
{
    public partial class FindDialogBox : Window
    {

        void findNextButton_Click(object sender, RoutedEventArgs e)
        {
                // Text found
                this.index = match.Index;
                this.length = match.Length;
                OnTextFound();
        }
    }
}
Imports System.Windows
Imports System.Windows.Controls
Imports System.Text.RegularExpressions

Namespace SDKSample

    Public Class FindDialogBox
        Inherits Window



            Me.Index = match.Index
            Me.Length = match.Length
            RaiseEvent TextFound(Me, EventArgs.Empty)

    End Class
End Namespace

そのとき、所有者ウィンドウは、このイベントを登録し、処理する必要があります。

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;

namespace SDKSample
{
    public partial class MainWindow : Window
    {

        void dlg_TextFound(object sender, EventArgs e)
        {
            // Get the find dialog box that raised the event
            FindDialogBox dlg = (FindDialogBox)sender;

            // Get find results and select found text
            this.documentTextBox.Select(dlg.Index, dlg.Length);
            this.documentTextBox.Focus();
        }
    }
}
Imports System.ComponentModel
Imports System.Windows
Imports System.Windows.Controls
Imports Microsoft.Win32

Namespace SDKSample
    Public Class MainWindow
        Inherits Window
        
        Private Sub dlg_TextFound(ByVal sender As Object, ByVal e As EventArgs)
            Dim dlg As FindDialogBox = DirectCast(sender, FindDialogBox)
            Me.documentTextBox.Select(dlg.Index, dlg.Length)
            Me.documentTextBox.Focus()
        End Sub
    End Class
End Namespace

モードレス ダイアログ ボックスを閉じる

DialogResult は設定する必要がないため、モードレス ダイアログ ボックスは、次のような、システムによって提供されるメカニズムを使用して閉じることができます。

  • タイトル バーの [閉じる] ボタンをクリックする。

  • Alt キーを押しながら F4 キーを押す。

  • [システム] メニューの [閉じる] を選択する。

または、 [閉じる] ボタンがクリックされたときに、コードから Close を呼び出すことができます。

using System;
using System.Windows;
using System.Windows.Controls;
using System.Text.RegularExpressions;

namespace SDKSample
{
    public partial class FindDialogBox : Window
    {

        void closeButton_Click(object sender, RoutedEventArgs e)
        {
            // Close dialog box
            this.Close();
        }
    }
}
Imports System.Windows
Imports System.Windows.Controls
Imports System.Text.RegularExpressions

Namespace SDKSample

    Public Class FindDialogBox
        Inherits Window

        Private Sub closeButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            MyBase.Close()
        End Sub
    End Class
End Namespace

関連項目