대화 상자 개요
독립 실행형 응용 프로그램에는 일반적으로 응용 프로그램이 작동하는 주 데이터를 표시하고 메뉴 모음, 도구 모음 및 상태 표시줄과 같은 user interface (UI) 메커니즘을 통해 데이터를 처리하는 기능을 노출하는 주 창이 있습니다. 또한 특수한 응용 프로그램은 다음을 수행하기 위한 추가 창을 표시할 수 있습니다.
특정 정보를 사용자에게 표시
사용자로부터 정보 수집
정보 표시 및 수집
이러한 유형의 창을 대화 상자라고 하며 두 가지 형식으로 모달 및 모덜리스가 있습니다.
사용자가 작업을 계속 수행하도록 함수에 추가 데이터가 필요한 경우 함수는 모달 대화 상자를 표시합니다. 함수가 모달 대화 상자에 종속되어 데이터를 수집하므로 모달 대화 상자가 열려 있는 동안에는 사용자가 응용 프로그램에서 다른 창을 활성화하지 못하게 합니다. 대부분의 경우 모달 대화 상자에서 사용자가 확인 또는 취소 단추를 눌러야 모달 대화 상자가 종료되었음을 알릴 수 있습니다. 확인 단추를 누르면 사용자가 데이터를 입력했으며 해당 데이터를 사용하여 함수에서 계속 처리하기를 원한다는 것을 나타냅니다. 취소 단추를 누르면 사용자가 함수의 실행을 완전히 중단하기를 원한다는 것을 나타냅니다. 모달 대화 상자의 가장 일반적인 예로 데이터 열기, 저장 및 인쇄를 위해 표시되는 대화 상자가 이에 해당합니다.
반면, 모덜리스 대화 상자는 이 대화 상자가 열려 있는 동안에도 사용자가 다른 창을 활성화할 수 있습니다. 예를 들어 사용자가 문서에서 특정 단어를 찾으려는 경우 주 창에 사용자가 찾으려는 단어를 입력하도록 열리는 대화 상자가 이에 해당합니다. 단어를 찾을 때 사용자가 문서를 편집하는 것이 허용되므로 대화 상자는 모달일 필요가 없습니다. 모덜리스 대화 상자는 최소한 대화 상자를 닫기 위한 닫기 단추를 제공하며 특정 함수를 실행하기 위한 추가 단추(예: 단어 검색의 찾기 조건과 일치하는 다음 단어를 찾는 다음 찾기 단추)를 제공할 수 있습니다.
Windows Presentation Foundation (WPF)에서는 메시지 상자, 일반 대화 상자 및 사용자 지정 대화 상자를 비롯한 여러 형식의 대화 상자를 만들 수 있습니다. 이 항목에서는 각 형식에 대해 설명하고, Dialog Box 샘플에서 관련 예제를 제공합니다.
이 항목에는 다음 단원이 포함되어 있습니다.
- 메시지 상자
- 일반 대화 상자
- 사용자 지정 대화 상자
- 관련 항목
메시지 상자
메시지 상자는 텍스트 정보를 표시하고 사용자가 단추를 사용하여 수행할 작업에 대한 결정을 내릴 수 있게 하는 대화 상자입니다. 다음 그림에서는 텍스트 정보를 표시하고 질문을 하며 해당 질문에 대답하기 위한 세 개의 단추를 제공하는 메시지 상자를 보여 줍니다.
메시지 상자를 만들려면 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 샘플 및 Dialog Box 샘플을 참조하십시오.
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를 사용하여 사용자 지정 모달 및 모덜리스 대화 상자를 만들 수 있습니다.
모달 사용자 지정 대화 상자 만들기
이 항목에서는 Margins 대화 상자를 예제로 사용하여(Dialog Box 샘플 참조) Window를 통해 일반적인 모달 대화 상자 구현을 만드는 방법을 보여 줍니다. Margins 대화 상자는 다음 그림과 같습니다.
모달 대화 상자 구성
일반적인 대화 상자의 사용자 인터페이스에는 다음이 포함됩니다.
원하는 데이터를 수집하는 데 필요한 다양한 컨트롤
사용자가 클릭했을 때 대화 상자를 닫고 함수로 돌아가 처리를 계속하는 확인 단추 표시
사용자가 클릭했을 때 대화 상자를 닫고 함수가 더 이상 처리되지 않도록 중지하는 취소 단추 표시
제목 표시줄에 닫기 단추 표시
아이콘 표시
최소화, 최대화 및 복원 단추 표시
대화 상자를 최소화, 최대화, 복원 및 닫기 위한 시스템 메뉴 표시
대화 상자를 연 창의 위쪽 및 가운데에서 열기
대화 상자가 너무 작아지지 않도록 가능한 위치에서 대화 상자의 크기를 조정할 수 있어야 하며 사용자에게 유용한 기본 크기를 제공하기 위해 기본 및 최소 크기를 각각 설정해야 합니다.
Esc 키 누르기를 바로 가기 키로 구성하여 취소 단추를 누른 것처럼 작동하도록 해야 합니다. 이렇게 하려면 취소 단추의 IsCancel 속성을 true로 설정합니다.
Enter 또는 Return 키 누르기를 바로 가기 키로 구성하여 확인 단추를 누른 것처럼 작동하도록 해야 합니다. 이렇게 하려면 확인 단추의 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 메서드를 호출하여 모달로 표시됩니다.
사용자 제공 데이터의 유효성 검사
대화 상자가 열리고 사용자가 필수 데이터를 제공할 경우 다음과 같은 이유로 대화 상자에서는 제공된 데이터가 유효한지 확인합니다.
보안 관점상, 모든 입력의 유효성을 검사해야 합니다.
도메인별 관점상, 데이터 유효성 검사를 수행하여 코드에 의해 오류 데이터가 처리되어 잠재적으로 예외가 thorw되는 상황을 방지해야 합니다.
사용자 경험 관점상, 대화 상자에서 사용자가 입력한 데이터가 잘못되었음을 표시하여 사용자에게 수정하도록 도움을 줄 수 있어야 합니다.
성능 관점상, 다중 계층 응용 프로그램에서의 데이터 유효성 검사를 수행하여 특히, 응용 프로그램이 웹 서비스 또는 서버 기반 데이터베이스로 구성된 경우 클라이언트 및 응용 프로그램 계층 간에 라운드트립 수를 줄일 수 있어야 합니다.
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에서 사용자는 유효한 데이터를 입력할 때까지 잘못된 컨트롤로 인해 제한받지 않습니다. 이는 대화 상자에 적합한 동작으로 즉, 사용자는 데이터가 유효한지 여부에 상관없이 대화 상자에서 컨트롤을 자유롭게 이동할 수 있습니다. 그러나 이는 사용자가 잘못된 데이터를 입력하고 확인 단추를 누를 수 있음을 의미하기도 합니다. 이러한 이유 때문에 코드에서는 Click 이벤트를 처리하여 확인 단추가 눌러졌을 때에도 대화 상자의 모든 컨트롤에 대한 유효성 검사를 수행합니다.
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가 반환될 경우 이를 호출한 코드는 사용자가 확인 단추를 눌렀는지 아니면 취소 단추를 눌렀는지에 따라 처리를 계속할지 아니면 중지할지를 결정합니다. 이 결정을 위해 대화 상자는 ShowDialog 메서드에서 반환된 Boolean 값을 사용자의 선택 항목으로 반환해야 합니다.
확인 단추를 클릭할 경우 ShowDialog는 true를 반환해야 합니다. 이 작업은 확인 단추를 클릭했을 때 대화 상자의 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인 경우 함수는 처리를 적절하게 끝내야 합니다.
모덜리스 사용자 지정 대화 상자 만들기
다음 그림처럼 찾기 대화 상자와 같은 모덜리스 대화 상자는 모달 대화 상자와 동일한 기본 모양을 가집니다.
그러나 다음 단원에 설명된 것처럼 동작이 약간 다릅니다.
모덜리스 대화 상자 열기
모덜리스 대화 상자는 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는 특정 빈도 없이 검색되는 텍스트에 따라 하나 이상의 찾기 결과를 주 창에 반환할 수 있습니다. 모달 대화 상자와 마찬가지로 모덜리스 대화 상자는 속성을 사용하여 결과를 반환할 수 있습니다. 그러나 대화 상자를 소유하는 창은 이러한 속성을 검사할 시점을 알아야 합니다. 이에 대한 한 가지 방법은 텍스트가 발견될 때마다 발생하는 이벤트를 대화 상자에서 구현하는 것입니다. 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();
}
}
}