ダイアログ ボックスの概要
通常、スタンドアロン アプリケーションにはメイン ウィンドウがあります。ここには、アプリケーションが処理を行うメイン データが表示されるほか、メニュー バー、ツール バー、ステータス バーのようなuser interface (UI) メカニズムによってそのデータを処理する機能も表示されます。 また、高度なアプリケーションでは、次の処理を行うウィンドウも表示されます。
ユーザーに特定の情報を表示する。
ユーザーから情報を収集する。
情報の表示と収集の両方を行う。
これらの種類のウィンドウは、ダイアログ ボックスと呼ばれ、モーダルおよびモードレスの 2 種類があります。
モーダル ダイアログ ボックスは、関数が続行するためにユーザーからの追加データを必要とする場合に、関数により表示されます。 関数は、データを収集するためにモーダル ダイアログ ボックスを必要とするため、このダイアログ ボックスが開いている間、ユーザーはアプリケーションで他のウィンドウをアクティブにすることができません。 ほとんどの場合、モーダル ダイアログ ボックスでは、ユーザーが [OK] ボタンまたは [キャンセル] ボタンをクリックすることにより、モーダル ダイアログ ボックスを終了することを通知できます。 [OK] ボタンのクリックは、ユーザーがデータの入力を完了し、関数がそのデータの処理を継続することを示します。 [キャンセル] ボタンのクリックは、関数が実行を完全に停止することを意味します。 モーダル ダイアログ ボックスの最も一般的な例は、データを開く、保存する、および印刷するダイアログ ボックスです。
一方、モードレス ダイアログ ボックスでは、このダイアログ ボックスが開いている間、ユーザーが他のウィンドウをアクティブにすることができます。 たとえば、ユーザーがドキュメント内で特定の単語の出現箇所を検索する場合は、一般に、メイン ウィンドウ上に検索対象の単語の入力を求めるダイアログ ボックスが開きます。 ただし、単語の検索中でもユーザーがドキュメントを編集することはできるので、このダイアログ ボックスがモーダルである必要はありません。 モードレス ダイアログ ボックスには、少なくともダイアログ ボックスを閉じるための閉じるボタンがあります。また、単語検索の検索条件と一致する次の単語を検索する [次を検索] ボタンなど、特定の関数を実行する他のボタンが存在することもあります。
Windows Presentation Foundation (WPF) では、メッセージ ボックス、コモン ダイアログ ボックス、カスタム ダイアログ ボックスなど、複数の種類のダイアログ ボックスを作成できます。 ここでは、それぞれのダイアログ ボックスの種類について説明します。各種類に対応するサンプルについては、ダイアログ ボックスのサンプルを参照してください。
このトピックは、次のセクションで構成されています。
- メッセージ ボックス
- コモン ダイアログ ボックス
- カスタム ダイアログ ボックス
- 関連トピック
メッセージ ボックス
メッセージ ボックスは、テキスト情報を表示し、ユーザーにボタンによる判断を求めるために使用できるダイアログ ボックスです。 テキスト情報を表示し、質問を表示したうえで、質問に回答するための 3 つのボタンを表示するメッセージ ボックスを次の図に示します。
メッセージ ボックスを作成するには、MessageBox クラスを使用します。 MessageBox クラスを使用すると、次のようなコードを使用して、メッセージ ボックスのテキスト、タイトル、アイコン、およびボタンを構成できます。
' 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
// 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;
メッセージ ボックスを表示するには、次のコードに示すように static Show メソッドを呼び出します。
' Display message box
MessageBox.Show(messageBoxText, caption, button, icon)
// Display message box
MessageBox.Show(messageBoxText, caption, button, icon);
メッセージ ボックスを表示するコードが、ユーザーの決定 (ボタンを押す) の検出と処理を行う必要がある場合、コードは次のコードに示すようにメッセージ ボックスの結果を検査できます。
' 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
// 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;
}
メッセージ ボックスの使い方の詳細については、MessageBox、メッセージ ボックスのサンプルおよびダイアログ ボックスのサンプルを参照してください。
MessageBox を使用すると、ダイアログ ボックスの単純なユーザー エクスペリエンスを実現できますが、MessageBox を使用することの利点は、XAML browser applications (XBAPs) などの部分信頼セキュリティ サンドボックス内で実行されているアプリケーションによって表示可能なウィンドウは、このウィンドウだけであるという点です (「セキュリティ (WPF)」を参照してください)。
テキスト、選択 (チェック ボックス)、相互に排他的な選択 (ラジオ ボタン)、およびリスト選択 (リスト ボックス、コンボ ボックス、ドロップダウン リスト ボックス) など、ほとんどのダイアログ ボックスは、メッセージ ボックスの結果よりも複雑なデータを表示および収集します。 このため、Windows Presentation Foundation (WPF) では、いくつかのコモン ダイアログ ボックスが用意されているだけでなく、独自のダイアログ ボックスを作成することもできます。ただし、どのダイアログ ボックスを使用する場合も、完全信頼で実行されるアプリケーションだけに制限されます。
コモン ダイアログ ボックス
Windows は、ファイルを開く、保存する、印刷するためのダイアログ ボックスなど、すべてのアプリケーションに共通の各種の再利用可能なダイアログ ボックスを実装しています。 これらのダイアログ ボックスはオペレーティング システムにより実装されるため、オペレーティング システムで実行されるすべてのアプリケーション間で共有できます。これは、ユーザー エクスペリエンスを一貫したものにするのに役立ちます。ユーザーが、オペレーティング システムで用意されているダイアログ ボックスを、特定のアプリケーションで使い慣れている場合、他のアプリケーションでそのダイアログ ボックスの使用方法を学習する必要はありません。 これらのダイアログ ボックスはすべてのアプリケーションで使用でき、一貫したユーザー エクスペリエンスを提供するのに役立つため、コモン ダイアログ ボックスと呼ばれます。
Windows Presentation Foundation (WPF) では、ファイルを開く、保存する、印刷するためのコモン ダイアログ ボックスが、スタンドアロン アプリケーションで使用できるように、カプセル化され、マネージ クラスとして表示されています。 ここでは、各ダイアログ ボックスについて簡単に説明します。
ファイルを開くダイアログ ボックス
ファイルを開くダイアログ ボックス (次の図を参照) は、開くファイルの名前を取得するために、ファイルを開く機能によって使用されます。
ファイルを開くコモン ダイアログ ボックスは OpenFileDialog クラスとして実装され、Microsoft.Win32 名前空間に存在します。 この種類のダイアログ ボックスを作成、構成、および表示して、結果を処理する方法を次のコード例に示します。
' 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
// 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;
}
ファイルを開くダイアログ ボックスの詳細については、Microsoft.Win32.OpenFileDialog を参照してください。
メモ |
---|
OpenFileDialog は、部分信頼で実行されているアプリケーションで安全にファイル名を取得するために使用できます (「セキュリティ (WPF)」を参照してください)。 |
ファイルの保存ダイアログ ボックス
ファイルの保存ダイアログ ボックス (次の図を参照) は、保存するファイルの名前を取得するために、ファイルの保存機能によって使用されます。
ファイルの保存コモン ダイアログ ボックスは SaveFileDialog クラスとして実装され、Microsoft.Win32 名前空間に存在します。 この種類のダイアログ ボックスを作成、構成、および表示して、結果を処理する方法を次のコード例に示します。
' Configure save file dialog box
Dim dlg As New Microsoft.Win32.SaveFileDialog()
dlg.FileName = "Document" ' Default file name
dlg.DefaultExt = ".text" ' 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
// Configure save file dialog box
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".text"; // 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;
}
ファイルの保存ダイアログ ボックスの詳細については、Microsoft.Win32.SaveFileDialog を参照してください。
印刷ダイアログ ボックス
印刷ダイアログ ボックス (次の図を参照) は、ユーザーがデータの印刷に使用するプリンターを選択および構成するために、印刷機能によって使用されます。
印刷コモン ダイアログ ボックスは PrintDialog クラスとして実装され、System.Windows.Controls 名前空間に存在します。 この種類のダイアログ ボックスを作成、構成、および表示する方法を次のコード例に示します。
' 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
// 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
}
印刷ダイアログ ボックスの詳細については、System.Windows.Controls.PrintDialog を参照してください。 WPF での印刷の詳細については、「印刷の概要」を参照してください。
カスタム ダイアログ ボックス
コモン ダイアログ ボックスは便利で、可能な場合は使用することをお勧めしますが、ドメイン固有のダイアログ ボックスの要件はサポートしていません。 そのような場合は、独自のダイアログ ボックスを作成する必要があります。 次に示すように、ダイアログ ボックスは特殊な処理を行うウィンドウです。 Window はそのような処理を実装するため、カスタムのモーダル ダイアログ ボックスおよびモードレス ダイアログ ボックスを作成するには、Window を使用します。
モーダル カスタム ダイアログ ボックスの作成
このトピックでは、Window を使用して一般的なモーダル ダイアログ ボックス実装を作成する方法について説明します。Margins ダイアログ ボックスを例として使用します (ダイアログ ボックスのサンプルを参照してください)。 Margins ダイアログ ボックスを次の図に示します。
モーダル ダイアログ ボックスの構成
一般的なダイアログ ボックスのユーザー インターフェイスには、次のような機能および条件があります。
必要なデータを収集するのに必要な各種のコントロール。
ユーザーがダイアログ ボックスを閉じ、関数に戻って処理を続行するための [OK] ボタンを表示する。
ユーザーがダイアログ ボックスを閉じ、関数の処理を停止するための [キャンセル] ボタンを表示する。
タイトル バーに閉じるボタンを表示する。
アイコンを表示する。
最小化ボタン、最大化ボタン、および元に戻すボタンを表示する。
ダイアログ ボックスを最小化、最大化、元に戻す、および閉じるためのシステム メニューを表示する。
ダイアログ ボックスを開いたウィンドウの上および中央で開く。
ダイアログ ボックスは可能な場合はサイズを変更できる必要があり、ダイアログ ボックスが小さくなりすぎないように、および使用しやすい既定のサイズを提供するために、既定のサイズと最小サイズの両方をそれぞれ設定しておく必要があります。
Esc キーを押す操作は、[キャンセル] ボタンをクリックするショートカット キーとして構成する。 これは、[キャンセル] ボタンの IsCancel プロパティを true に設定することによって行います。
Enter (または Return) キーを押す操作は、[OK] ボタンをクリックするショートカット キーとして構成する。 これは、[OK] ボタンの IsDefault プロパティを true に設定することによって行います。
この構成の例を次に示します。
<Window
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://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>
Imports System.Windows ' Window, RoutedEventArgs, IInputElement, DependencyObject
Imports System.Windows.Controls ' Validation
Imports System.Windows.Input ' Keyboard
Namespace SDKSample
Public Class MarginsDialogBox
Inherits Window
Public Sub New()
Me.InitializeComponent()
End Sub
...
End Class
End Namespace
using System.Windows; // Window, RoutedEventArgs, IInputElement, DependencyObject
using System.Windows.Controls; // Validation
using System.Windows.Input; // Keyboard
namespace SDKSample
{
public partial class MarginsDialogBox : Window
{
public MarginsDialogBox()
{
InitializeComponent();
}
...
}
}
ダイアログ ボックスに関するユーザー エクスペリエンスは、ダイアログ ボックスを開くウィンドウのメニュー バーにも及びます。 関数が続行するためにダイアログ ボックスを介したユーザー操作を必要とする関数が、メニュー項目により実行された場合、この例に示されているように関数のメニュー項目のヘッダーに省略記号が表示されます。
<!--Main Window-->
...
<MenuItem Name="formatMarginsMenuItem" Header="_Margins..." Click="formatMarginsMenuItem_Click" />
[バージョン情報] ダイアログ ボックスなど、ユーザー操作を必要としないダイアログ ボックスを表示する関数がメニュー項目により実行された場合、省略記号は不要です。
モーダル ダイアログ ボックスを開く
ダイアログ ボックスは、ワード プロセッサで文書の余白を設定するなど、通常ユーザーがメニュー項目を選択してドメイン固有の関数を実行した結果として表示されます。 ウィンドウをダイアログ ボックスとして表示することは、通常のウィンドウを表示するのと同様ですが、ダイアログ ボックス固有の追加構成が必要です。 ダイアログ ボックスを初期化する、構成する、および開く処理全体を次のコード例に示します。
Imports System ' EventArgs
Imports System.ComponentModel ' CancelEventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextChangedEventArgs
Imports Microsoft.Win32 ' OpenFileDialog
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
using System; // EventArgs
using System.ComponentModel; // CancelEventArgs
using System.Windows; // Window, MessageBoxXxx, RoutedEventArgs
using System.Windows.Controls; // TextChangedEventArgs
using Microsoft.Win32; // OpenFileDialog
namespace SDKSample
{
public partial class MainWindow : Window
{
...
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();
...
}
...
}
}
ここでは、このコードはダイアログ ボックスに既定の情報 (現在の余白) を渡しています。 また、Window.Owner プロパティに、ダイアログ ボックスを表示しているウィンドウへの参照も設定しています。 通常、すべてのダイアログ ボックスに共通する、ウィンドウの状態関連の動作を提供するには、必ずダイアログ ボックスの所有者を設定する必要があります (詳細については「WPF ウィンドウの概要」を参照してください)。
メモ |
---|
ダイアログ ボックスでuser interface (UI) オートメーションをサポートするには、所有者を指定する必要があります (「UI オートメーションの概要」を参照してください)。 |
ダイアログ ボックスを構成した後で ShowDialog メソッドを呼び出すと、ダイアログ ボックスがモーダルで表示されます。
ユーザー指定のデータの検証
ダイアログ ボックスが開き、ユーザーが必要なデータを入力する際、次の理由により、ダイアログ ボックスは入力されたデータが有効であることを確認する必要があります。
セキュリティ上の観点から、すべての入力を検証する必要があります。
ドメイン固有の観点では、データを検証することで、誤入力データがコードで処理されたため、例外がスローされる可能性を排除します。
ユーザー エクペリエンスの観点では、入力データの中で間違っていたものを表示することによって、ユーザーを支援します。
パフォーマンスの観点では、多階層アプリケーションでデータを検証することで、特にアプリケーションが Web サービスまたはサーバー ベースのデータベースで構成されている場合に、クライアント層とアプリケーション層の間のラウンド トリップ数が減少します。
WPF でバインドされたコントロールを検証するには、検証規則を作成し、その規則を該当するバインディングに関連付ける必要があります。検証規則は ValidationRule から派生するカスタム クラスです。 バインドされた値が Double であり、指定した範囲内にあることを確認する MarginValidationRule を次の例に示します。
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
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);
}
}
}
このコードでは、データを検証して該当する ValidationResult を返す Validate メソッドをオーバーライドすることにより、検証規則の検証ロジックが実装されます。
バインドされたコントロールに検証規則を関連付けるには、次のマークアップを使用します。
<Window
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://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>
...
<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>
...
</Window>
検証規則を関連付けた後、バインドされたコントロールにデータが入力されると、WPF は検証規則を自動的に適用します。 コントロールに無効なデータが含まれている場合、次の図に示すように、WPF は無効なコントロールの周りに赤い境界線を表示します。
WPF では、有効なデータが入力されるまでユーザーを無効なコントロールに縛り付けることはありません。 この動作はダイアログ ボックスに適しています。ユーザーは、入力したデータが有効かどうかに関係なく、ダイアログ ボックス内のコントロール群を自由に移動できる必要があります。 ただし、これは、ユーザーが無効なデータを入力して [OK] ボタンをクリックできることを意味します。 したがって、Click イベントを処理することにより [OK] ボタンがクリックされた場合、コードでダイアログ ボックス内のすべてのコントロールを検証することも必要です。
Imports System.Windows ' Window, RoutedEventArgs, IInputElement, DependencyObject
Imports System.Windows.Controls ' Validation
Imports System.Windows.Input ' Keyboard
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
using System.Windows; // Window, RoutedEventArgs, IInputElement, DependencyObject
using System.Windows.Controls; // Validation
using System.Windows.Input; // Keyboard
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;
}
}
}
このコードは、ウィンドウ上のすべての依存関係オブジェクトを列挙します。無効なオブジェクトがある場合は (GetHasError によって返される値で判断)、無効なコントロールがフォーカスを取得し、IsValid メソッドが false を返し、ウィンドウが無効と見なされます。
ダイアログ ボックスが有効である場合は、安全に閉じ、制御を返すことができます。 返す処理の一部として、結果を呼び出し元の関数に返す必要があります。
モーダル ダイアログ ボックスの結果の設定
ShowDialog を使用してダイアログ ボックスを開くのは、基本的にはメソッドの呼び出しと似ています。ShowDialog を使用してダイアログ ボックスを開いたコードは、ShowDialog から制御が返されるまで待機します。 ShowDialog から制御が返されると、呼び出し元のコードは、ユーザーが [OK] ボタンをクリックしたか [キャンセル] ボタンをクリックしたかに基づいて、処理を続行するか停止するかを決定する必要があります。 この決定を行いやすくするため、ダイアログ ボックスはユーザーの選択内容を、ShowDialog メソッドから返された Boolean 値として返す必要があります。
[OK] ボタンがクリックされた場合、ShowDialog は true を返す必要があります。 これは、[OK] ボタンがクリックされた場合のダイアログ ボックスの DialogResult プロパティを設定することによって行います。
DialogResult プロパティを設定すると、ウィンドウが自動的に閉じられるため、Close を明示的に呼び出す手間を省くことができます。
[キャンセル] ボタンがクリックされた場合、ShowDialog は false を返す必要があります。さらに、DialogResult プロパティも設定する必要があります。
Imports System.Windows ' Window, RoutedEventArgs, IInputElement, DependencyObject
Imports System.Windows.Controls ' Validation
Imports System.Windows.Input ' Keyboard
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
using System.Windows; // Window, RoutedEventArgs, IInputElement, DependencyObject
using System.Windows.Controls; // Validation
using System.Windows.Input; // Keyboard
namespace SDKSample
{
public partial class MarginsDialogBox : Window
{
...
void cancelButton_Click(object sender, RoutedEventArgs e)
{
// Dialog box canceled
this.DialogResult = false;
}
...
}
}
ボタンの IsCancel プロパティが true に設定された状態で、ユーザーが [キャンセル] ボタンまたは Esc キーを押した場合は、DialogResult が自動的に false に設定されます。 次のマークアップには、Click イベントを処理しなくても、前のコードと同じ効果があります。
<Button Name="cancelButton" IsCancel="True">Cancel</Button>
ダイアログ ボックスは、ユーザーがタイトル バーの閉じるボタンをクリックするか、システム メニューの [閉じる] メニュー項目を選択すると、結果として自動的に false を返します。
モーダル ダイアログ ボックスから返されたデータの処理
DialogResult がダイアログ ボックスによって設定されると、ダイアログ ボックスを開いた関数は、ShowDialog から制御が返されたときに、DialogResult プロパティを調べてそのダイアログ ボックスの結果を取得できます。
Imports System ' EventArgs
Imports System.ComponentModel ' CancelEventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextChangedEventArgs
Imports Microsoft.Win32 ' OpenFileDialog
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
using System; // EventArgs
using System.ComponentModel; // CancelEventArgs
using System.Windows; // Window, MessageBoxXxx, RoutedEventArgs
using System.Windows.Controls; // TextChangedEventArgs
using Microsoft.Win32; // OpenFileDialog
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;
}
}
...
}
}
ダイアログの結果が true になった場合、関数はユーザーが入力した値の取得および処理を開始します。
メモ |
---|
ShowDialog から制御が返された後は、ダイアログ ボックスを再度開くことはできません。代わりに、新しいインスタンスを作成する必要があります。 |
ダイアログの結果が false の場合、関数は処理を適切に終了する必要があります。
モードレス カスタム ダイアログ ボックスの作成
次の図に示されている FindDialogBox のようなモードレス ダイアログ ボックスは、基本的な外観はモーダル ダイアログ ボックスと同じです。
ただし、以下のセクションで説明するように、動作は若干異なります。
モードレス ダイアログ ボックスを開く
モードレス ダイアログ ボックスは Show メソッドを呼び出すことによって開かれます。
<!--Main Window-->
Imports System ' EventArgs
Imports System.ComponentModel ' CancelEventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextChangedEventArgs
Imports Microsoft.Win32 ' OpenFileDialog
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
using System; // EventArgs
using System.ComponentModel; // CancelEventArgs
using System.Windows; // Window, MessageBoxXxx, RoutedEventArgs
using System.Windows.Controls; // TextChangedEventArgs
using Microsoft.Win32; // OpenFileDialog
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();
}
...
}
}
ShowDialog とは異なり、Show はすぐに制御が戻ります。 このため、呼び出し元のウィンドウは、モードレス ダイアログ ボックスが閉じられるタイミングを判別できません。したがって、ダイアログ ボックスの結果を確認したり、ダイアログ ボックスからデータを取得してさらに処理したりするタイミングも認識できません。 ダイアログ ボックスは、呼び出し元のウィンドウにデータを返して処理を託すために、別の方法を用意する必要があります。
モードレス ダイアログ ボックスから返されたデータの処理
この例では、FindDialogBox は、頻度を特に指定せずに検索されているテキストに応じて、1 つ以上の検索結果をメイン ウィンドウに返す場合があります。 モーダル ダイアログ ボックスと同様に、モードレス ダイアログ ボックスはプロパティを使用して結果を返すことができます。 ただし、ダイアログ ボックスを所有しているウィンドウで、これらのプロパティを確認するタイミングを認識できる必要があります。 これを実現する方法の 1 つは、テキストが検出されるたびに発生するイベントをダイアログ ボックスに実装することです。 FindDialogBox はこの目的で TextFoundEvent を実装します。これには、まずデリゲートが必要です。
Namespace SDKSample
Public Delegate Sub TextFoundEventHandler(ByVal sender As Object, ByVal e As EventArgs)
End Namespace
using System;
namespace SDKSample
{
public delegate void TextFoundEventHandler(object sender, EventArgs e);
}
TextFoundEventHandler デリゲートを使用して、FindDialogBox は TextFoundEvent を実装します。
Imports System ' EventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextBox, TextChangedEventArgs
Imports System.Text.RegularExpressions ' Regex
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
using System; // EventArgs
using System.Windows; // Window, MessageBoxXxx, RoutedEventArgs
using System.Windows.Controls; // TextBox, TextChangedEventArgs
using System.Text.RegularExpressions; // Regex
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);
}
...
}
}
これにより、Find は検索結果が見つかったときに、このイベントを発生させることができます。
Imports System ' EventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextBox, TextChangedEventArgs
Imports System.Text.RegularExpressions ' Regex
Namespace SDKSample
Public Class FindDialogBox
Inherits Window
...
Private Sub findNextButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
...
Me.Index = match.Index
Me.Length = match.Length
RaiseEvent TextFound(Me, EventArgs.Empty)
...
End Sub
...
End Class
End Namespace
using System; // EventArgs
using System.Windows; // Window, MessageBoxXxx, RoutedEventArgs
using System.Windows.Controls; // TextBox, TextChangedEventArgs
using System.Text.RegularExpressions; // Regex
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 ' EventArgs
Imports System.ComponentModel ' CancelEventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextChangedEventArgs
Imports Microsoft.Win32 ' OpenFileDialog
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
using System; // EventArgs
using System.ComponentModel; // CancelEventArgs
using System.Windows; // Window, MessageBoxXxx, RoutedEventArgs
using System.Windows.Controls; // TextChangedEventArgs
using Microsoft.Win32; // OpenFileDialog
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();
}
}
}
モードレス ダイアログ ボックスを閉じる
DialogResult を設定する必要はないため、モードレス ダイアログ ボックスは、システムに用意されている次のような機能を使用して閉じることができます。
タイトル バーの閉じるボタンをクリックする。
Alt キーを押しながら F4 キーを押す。
システム メニューの [閉じる] をクリックする。
または、閉じるボタンがクリックされたときに、コードによって Close を呼び出すことができます。
Imports System ' EventArgs
Imports System.Windows ' Window, MessageBoxXxx, RoutedEventArgs
Imports System.Windows.Controls ' TextBox, TextChangedEventArgs
Imports System.Text.RegularExpressions ' Regex
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
using System; // EventArgs
using System.Windows; // Window, MessageBoxXxx, RoutedEventArgs
using System.Windows.Controls; // TextBox, TextChangedEventArgs
using System.Text.RegularExpressions; // Regex
namespace SDKSample
{
public partial class FindDialogBox : Window
{
...
void closeButton_Click(object sender, RoutedEventArgs e)
{
// Close dialog box
this.Close();
}
}
}