对话框概述Dialog Boxes Overview

独立应用程序通常具有主窗口,同时显示的主数据,通过该应用程序进行运行,并将处理通过该数据的功能公开用户界面 (UI)user interface (UI)机制,如菜单栏、 工具栏和状态栏。Standalone applications typically have a main window that both displays the main data over which the application operates and exposes the functionality to process that data through 用户界面 (UI)user interface (UI) mechanisms like menu bars, tool bars, and status bars. 重要的应用程序可能还会显示其他窗口来执行以下操作:A non-trivial application may also display additional windows to do the following:

  • 向用户显示特定信息。Display specific information to users.

  • 从用户处收集信息。Gather information from users.

  • 同时显示并收集信息。Both display and gather information.

这些类型的 windows 称为对话框,并且有两种类型: 模式和无模式。These types of windows are known as dialog boxes, and there are two types: modal and modeless.

A模式函数需要用户继续从其他数据时,对话框将显示函数。A modal dialog box is displayed by a function when the function needs additional data from a user to continue. 由于函数依赖于模式对话框收集数据,模式对话框还会在其保持打开状态时防止用户激活应用程序中的其他窗口。Because the function depends on the modal dialog box to gather data, the modal dialog box also prevents a user from activating other windows in the application while it remains open. 在大多数情况下,模式对话框,用户可以发出信号时它们完成的模式对话框中按任一确定取消按钮。In most cases, a modal dialog box allows a user to signal when they have finished with the modal dialog box by pressing either an OK or Cancel button. 确定按钮指示用户输入了数据,想要继续处理该数据的函数。Pressing the OK button indicates that a user has entered data and wants the function to continue processing with that data. 取消按钮指示用户想要停止中一起执行的函数。Pressing the Cancel button indicates that a user wants to stop the function from executing altogether. 最常见的模式对话框示例显示为可以打开、保存并打印数据。The most common examples of modal dialog boxes are shown to open, save, and print data.

A无模式对话框中,另一方面,不会阻止用户激活其他窗口处于打开状态时。A modeless dialog box, on the other hand, does not prevent a user from activating other windows while it is open. 例如,如果用户想要在某个文档中查找特定字的出现次数,主窗口通常会打开一个对话框,询问用户要查找的字是什么。For example, if a user wants to find occurrences of a particular word in a document, a main window will often open a dialog box to ask a user what word they are looking for. 查找字并不会防止用户编辑文档,因此对话框无需为模式对话框。Since finding a word doesn't prevent a user from editing the document, however, the dialog box doesn't need to be modal. 无模式对话框至少提供关闭按钮以关闭对话框,并可能提供其他按钮来执行特定的功能,如查找下一个按钮以查找下一个词与 word 搜索查找条件匹配。A modeless dialog box at least provides a Close button to close the dialog box, and may provide additional buttons to execute specific functions, such as a Find Next button to find the next word that matches the find criteria of a word search.

Windows Presentation Foundation (WPF),可创建几种类型的对话框框中,包括消息框、 通用对话框和自定义对话框。Windows Presentation Foundation (WPF) allows you to create several types of dialog boxes, including message boxes, common dialog boxes, and custom dialog boxes. 本主题介绍了每一个,和对话框示例提供匹配的示例。This topic discusses each, and the Dialog Box Sample provides matching examples.

消息框Message Boxes

A消息框是可以用于显示文本的信息并允许用户通过按钮做出决定的对话框。A message box is a dialog box that can be used to display textual information and to allow users to make decisions with buttons. 下图显示的消息框显示文本信息、提出问题并向用户提供了三个按钮来回答问题。The following figure shows a message box that displays textual information, asks a question, and provides the user with three buttons to answer the question.

“字处理器”对话框Word Processor dialog box

若要创建一个消息框,你可以使用MessageBox类。To create a message box, you use the MessageBox class. MessageBox 可以配置消息框文本、 标题、 图标和按钮,使用代码如下所示。MessageBox lets you configure the message box text, title, icon, and buttons, using code like the following.

// 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方法,如下面的代码所示。To show a message box, you call the staticShow method, as demonstrated in the following code.

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

当显示消息框的代码需要检测并处理用户决定(按下了哪个按钮)时,该代码可以检查消息框的结果,如以下代码中所示。When code that shows a message box needs to detect and process the user's decision (which button was pressed), the code can inspect the message box result, as shown in the following code.

// 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

使用消息框的详细信息,请参阅MessageBoxMessageBox 示例,和对话框示例For more information on using message boxes, see MessageBox, MessageBox Sample, and Dialog Box Sample.

尽管MessageBox可提供简单对话框框中用户体验,使用的优点MessageBox是可以由在部分信任安全沙盒中运行的应用程序显示的窗口的唯一类型 (请参阅安全),如XAML 浏览器应用程序 (XBAP)XAML browser applications (XBAPs)Although MessageBox may offer a simple dialog box user experience, the advantage of using MessageBox is that is the only type of window that can be shown by applications that run within a partial trust security sandbox (see Security), such as XAML 浏览器应用程序 (XBAP)XAML browser applications (XBAPs).

大多数对话框显示和收集比消息框结果更复杂的数据,包括文本、选项(复选框)、互斥选项(单选按钮)和列表选项(列表框、组合框、下拉列表框)。Most dialog boxes display and gather more complex data than the result of a message box, including text, selection (check boxes), mutually exclusive selection (radio buttons), and list selection (list boxes, combo boxes, drop-down list boxes). 对于这些数据,Windows Presentation Foundation (WPF) 提供几个通用对话框,并允许你创建你自己的对话框,尽管这两类使用仅限于以完全信任运行的应用程序。For these, Windows Presentation Foundation (WPF) provides several common dialog boxes and allows you to create your own dialog boxes, although the use of either is limited to applications running with full trust.

通用对话框Common Dialog Boxes

WindowsWindows 实现所有应用程序(包括用于打开文件、保存文件和打印的对话框)共用的各种可重用的对话框。 implements a variety of reusable dialog boxes that are common to all applications, including dialog boxes for opening files, saving files, and printing. 这些对话框由操作系统实现,因此可以在运行于该操作系统上的所有应用程序之间共享,这对用户体验的一致性很有帮助;当用户熟悉一个应用程序中操作系统所提供的对话框时,他们就无需再去了解如何在其他应用程序中使用该对话框。Since these dialog boxes are implemented by the operating system, they can be shared among all the applications that run on the operating system, which helps user experience consistency; when users are familiar with the use of an operating system-provided dialog box in one application, they don't need to learn how to use that dialog box in other applications. 因为这些对话框可供所有应用程序,因为它可以帮助提供一致的用户体验,它们被称为通用对话框Because these dialog boxes are available to all applications and because they help provide a consistent user experience, they are known as common dialog boxes.

Windows Presentation Foundation (WPF) 封装打开的文件、 保存文件,并打印通用对话框并将它们公开为托管的类供你使用独立应用程序中。Windows Presentation Foundation (WPF) encapsulates the open file, save file, and print common dialog boxes and exposes them as managed classes for you to use in standalone applications. 本主题提供每个通用对话框的简要概述。This topic provides a brief overview of each.

打开文件对话框Open File Dialog

如下图中所示的打开文件对话框由文件打开功能用于检索要打开文件的名称。The open file dialog box, shown in the following figure, is used by file opening functionality to retrieve the name of a file to open.

打开对话框Open dialog box

作为实现通用的打开文件对话框OpenFileDialog类,且位于Microsoft.Win32命名空间。The common open file dialog box is implemented as the OpenFileDialog class and is located in the Microsoft.Win32 namespace. 以下代码显示了如何创建、配置和显示保存文件对话框以及如何处理结果。The following code shows how to create, configure, and show one, and how to process the result.

// 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.OpenFileDialogFor more information on the open file dialog box, see Microsoft.Win32.OpenFileDialog.

备注

OpenFileDialog 可以用于安全地检索文件的名称在部分信任运行的应用程序 (请参阅安全)。OpenFileDialog can be used to safely retrieve file names by applications running with partial trust (see Security).

保存文件对话框Save File Dialog Box

如下图中所示的保存文件对话框由文件保存功能用以检索要保存的文件的名称。The save file dialog box, shown in the following figure, is used by file saving functionality to retrieve the name of a file to save.

另存为对话框Save As dialog box

保存文件对话框中的常见实现为SaveFileDialog类,并且位于Microsoft.Win32命名空间。The common save file dialog box is implemented as the SaveFileDialog class, and is located in the Microsoft.Win32 namespace. 以下代码显示了如何创建、配置和显示保存文件对话框以及如何处理结果。The following code shows how to create, configure, and show one, and how to process the result.

// 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.SaveFileDialogFor more information on the save file dialog box, see Microsoft.Win32.SaveFileDialog.

如下图中所示的打印对话框由打印功能用以选择和配置用户想要将数据打印到的打印机。The print dialog box, shown in the following figure, is used by printing functionality to choose and configure the printer that a user would like to print data to.

打印对话框Print dialog box

作为实现通用打印对话框PrintDialog类,并且位于System.Windows.Controls命名空间。The common print dialog box is implemented as the PrintDialog class, and is located in the System.Windows.Controls namespace. 以下代码显示了如何创建、配置和显示打印对话框。The following code shows how to create, configure, and show one.

// 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.PrintDialogFor more information on the print dialog box, see System.Windows.Controls.PrintDialog. 有关详细讨论中的打印WPFWPF,请参阅打印概述For detailed discussion of printing in WPFWPF, see Printing Overview.

自定义对话框Custom Dialog Boxes

尽管通用对话框很有用并应尽可能使用,但它们并不支持特定于域的对话框的要求。While common dialog boxes are useful, and should be used when possible, they do not support the requirements of domain-specific dialog boxes. 在这些情况下,就需要创建自己的对话框。In these cases, you need to create your own dialog boxes. 如我们所见,对话框是具有特殊行为的窗口。As we'll see, a dialog box is a window with special behaviors. Window 实现这些行为和中,因此,使用Window创建自定义模式和无模式对话框。Window implements those behaviors and, consequently, you use Window to create custom modal and modeless dialog boxes.

创建模式自定义对话框Creating a Modal Custom Dialog Box

本主题演示如何使用Window创建一个典型的模式对话框框中实现,它使用Margins作为示例的对话框中 (请参阅对话框示例)。This topic shows how to use Window to create a typical modal dialog box implementation, using the Margins dialog box as an example (see Dialog Box Sample). Margins如下图中显示对话框。The Margins dialog box is shown in the following figure.

边距对话框Margins dialog box

配置模式对话框Configuring a Modal Dialog Box

典型对话框的用户界面包括以下内容:The user interface for a typical dialog box includes the following:

  • 收集所需数据要求的各种控件。The various controls that are required to gather the desired data.

  • 显示确定按钮用户单击以关闭对话框,返回到该功能,并继续进行处理。Showing an OK button that users click to close the dialog box, return to the function, and continue processing.

  • 显示取消用户单击来关闭对话框并停止进一步处理功能的按钮。Showing a Cancel button that users click to close the dialog box and stop the function from further processing.

  • 显示关闭标题栏中的按钮。Showing a Close button in the title bar.

  • 显示一个图标。Showing an icon.

  • 显示最小化最大化,和还原按钮。Showing Minimize, Maximize, and Restore buttons.

  • 显示系统菜单以最小化、 最大化、 还原和关闭对话框。Showing a System menu to minimize, maximize, restore, and close the dialog box.

  • 在打开对话框的窗口上方和中心打开。Opening above and in the center of the window that opened the dialog box.

  • 对话框应尽可能可以调整大小(以防对话框过小)并为用户提供合适的默认尺寸,需要分别设置默认和最小尺寸。Dialog boxes should be resizable where possible so, to prevent the dialog box from being too small, and to provide the user with a useful default size, you need to set both default and a minimum dimensions respectively.

  • 按 ESC 键应配置为与导致的键盘快捷方式取消按按钮。Pressing the ESC key should be configured as a keyboard shortcut that causes the Cancel button to be pressed. 这可通过设置IsCancel属性取消按钮trueThis is achieved by setting the IsCancel property of the Cancel button to true.

  • 按 ENTER 键 (或 RETURN) 键应配置为将导致的键盘快捷方式确定按按钮。Pressing the ENTER (or RETURN) key should be configured as a keyboard shortcut that causes the OK button to be pressed. 这可通过设置IsDefault属性确定按钮trueThis is achieved by setting the IsDefault property of the OK button true.

以下代码演示了这种配置。The following code demonstrates this configuration.


<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

对话框用户体验还扩展到打开对话框的窗口菜单栏。The user experience for a dialog box also extends into the menu bar of the window that opens the dialog box. 当菜单项运行需要用户通过对话框交互才能继续运行的函数时,函数的菜单项标题上会有一个省略号,如此处所示。When a menu item runs a function that requires user interaction through a dialog box before the function can continue, the menu item for the function will have an ellipsis in its header, as shown here.

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

当菜单项运行的函数显示无需用户交互的对话框(如“关于”对话框)时,则不需要省略号。When a menu item runs a function that displays a dialog box which does not require user interaction, such as an About dialog box, an ellipsis is not required.

打开模式对话框Opening a Modal Dialog Box

对话框通常显示为用户选择菜单项来执行特定于域的函数的结果,比如在字处理器中设置文档边距。A dialog box is typically shown as a result of a user selecting a menu item to perform a domain-specific function, such as setting the margins of a document in a word processor. 将窗口显示为对话框类似于显示普通窗口,只是它需要其他特定于对话框的配置。Showing a window as a dialog box is similar to showing a normal window, although it requires additional dialog box-specific configuration. 以下代码中显示了实例化、配置和打开对话框的整个过程。The entire process of instantiating, configuring, and opening a dialog box is shown in the following code.

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

namespace SDKSample
{
    public partial class MainWindow : Window
    {

Imports System
Imports System.ComponentModel
Imports System.Windows
Imports System.Windows.Controls
Imports Microsoft.Win32

Namespace SDKSample

Public Class MainWindow
    Inherits 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();

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

此处代码将默认信息(当前边距)传递给对话框。Here, the code is passing default information (the current margins) to the dialog box. 它设置Window.Owner具有对显示的对话框窗口的引用属性。It is also setting the Window.Owner property with a reference to the window that is showing the dialog box. 一般情况下,应始终设置对话框中提供窗口与状态相关的行为所共有的所有对话框的所有者 (请参阅WPF Windows 概述有关详细信息)。In general, you should always set the owner for a dialog box to provide window state-related behaviors that are common to all dialog boxes (see WPF Windows Overview for more information).

备注

必须提供一个所有者,以支持用户界面 (UI)user interface (UI)对话框自动化 (请参阅UI 自动化概述)。You must provide an owner to support 用户界面 (UI)user interface (UI) automation for dialog boxes (see UI Automation Overview).

配置对话框中后,它将显示有模式地通过调用ShowDialog方法。After the dialog box is configured, it is shown modally by calling the ShowDialog method.

验证用户提供的数据Validating User-Provided Data

当打开对话框并且用户提供所需数据时,对话框出于以下原因负责确保提供的数据有效:When a dialog box is opened and the user provides the required data, a dialog box is responsible for ensuring that the provided data is valid for the following reasons:

  • 从安全角度,应该验证所有输入。From a security perspective, all input should be validated.

  • 从特定于域的角度,数据验证可以防止代码处理错误数据,这可能引发异常。From a domain-specific perspective, data validation prevents erroneous data from being processed by the code, which could potentially throw exceptions.

  • 从用户体验角度,对话框可以帮助用户显示他们输入的哪些数据无效。From a user-experience perspective, a dialog box can help users by showing them which data they have entered is invalid.

  • 从性能角度,多层应用程序中的数据验证可以减少客户端和应用程序层之间的往返次数,尤其当应用程序由 Web 服务或基于服务器的数据库构成时。From a performance perspective, data validation in a multi-tier application can reduce the number of round trips between the client and the application tiers, particularly when the application is composed of Web services or server-based databases.

若要验证中的绑定的控件WPFWPF,你需要定义验证规则并将其与绑定相关联。To validate a bound control in WPFWPF, you need to define a validation rule and associate it with the binding. 验证规则是派生自的自定义类ValidationRuleA validation rule is a custom class that derives from ValidationRule. 下面的示例演示验证规则, MarginValidationRule,一个绑定的值的检查Double,并且在指定范围内。The following example shows a validation rule, MarginValidationRule, which checks that a bound value is a Double and is within a specified range.

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

在此代码中,验证规则的验证逻辑实现通过重写Validate方法,它的数据进行验证,并返回相应ValidationResultIn this code, the validation logic of a validation rule is implemented by overriding the Validate method, which validates the data and returns an appropriate ValidationResult.

要将验证规则与绑定控件进行关联,可以使用以下标记。To associate the validation rule with the bound control, you use the following markup.

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

一旦验证规则是相关联,WPFWPF会自动将它应用数据输入到绑定控件时。Once the validation rule is associated, WPFWPF will automatically apply it when data is entered into the bound control. 如果控件包含无效的数据,WPFWPF将红色的周围显示边框无效的控件,如下图中所示。When a control contains invalid data, WPFWPF will display a red border around the invalid control, as shown in the following figure.

无效左边距Invalid left margin

WPFWPF 不会在用户输入有效数据之前限制其对无效控件的访问。 does not restrict a user to the invalid control until they have entered valid data. 这对于对话框来说很好,无论数据是否有效用户都应该可以自由导航到对话框中的控件。This is good behavior for a dialog box; a user should be able to freely navigate the controls in a dialog box whether or not data is valid. 但是,这意味着用户可以输入无效数据,然后按确定按钮。However, this means a user can enter invalid data and press the OK button. 为此,你的代码还需要验证在对话框中的所有控件当确定按钮按下处理Click事件。For this reason, your code also needs to validate all controls in a dialog box when the OK button is pressed by handling the Click event.

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

namespace SDKSample
{
    public partial class MarginsDialogBox : Window
    {
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input

Namespace SDKSample


Public Class MarginsDialogBox
    Inherits Window
void okButton_Click(object sender, RoutedEventArgs e)
{
    // Don't accept the dialog box if there is invalid data
    if (!IsValid(this)) return;
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
        }

        // 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;
        }
    }
}
    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,和窗口被认为是无效。This code enumerates all dependency objects on a window and, if any are invalid (as returned by GetHasError, the invalid control gets the focus, the IsValid method returns false, and the window is considered invalid.

一旦对话框有效,就可以安全关闭并返回。Once a dialog box is valid, it can safely close and return. 作为返回过程的一部分,需要将结果返回到调用函数。As part of the return process, it needs to return a result to the calling function.

设置模式对话框结果Setting the Modal Dialog Result

打开对话框框中使用ShowDialog它基本上是像调用的方法: 打开对话框框中使用的代码ShowDialog将等待,直至ShowDialog返回。Opening a dialog box using ShowDialog is fundamentally like calling a method: the code that opened the dialog box using ShowDialog waits until ShowDialog returns. ShowDialog代码需要调用它以确定是否继续处理或停止处理,根据是否,则会返回用户按下确定按钮或取消按钮。When ShowDialog returns, the code that called it needs to decide whether to continue processing or stop processing, based on whether the user pressed the OK button or the Cancel button. 若要便于做出此决定,对话框中需要返回用户的选择为Boolean从返回的值ShowDialog方法。To facilitate this decision, the dialog box needs to return the user's choice as a Boolean value that is returned from the ShowDialog method.

确定单击按钮时,ShowDialog应返回trueWhen the OK button is clicked, ShowDialog should return true. 这可通过设置DialogResult属性对话框框中时确定单击按钮。This is achieved by setting the DialogResult property of the dialog box when the OK button is clicked.

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

namespace SDKSample
{
    public partial class MarginsDialogBox : Window
    {
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input

Namespace SDKSample


Public Class MarginsDialogBox
    Inherits Window
void okButton_Click(object sender, RoutedEventArgs e)
{
Private Sub okButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
    // Dialog box accepted
    this.DialogResult = true;
}
    ' Dialog box accepted
    MyBase.DialogResult = New Nullable(Of Boolean)(True)
End Sub
    }
}
End Class

End Namespace

请注意,设置DialogResult属性也会导致窗口的窗口自动关闭,减少了需要显式调用CloseNote that setting the DialogResult property also causes the window to close automatically, which alleviates the need to explicitly call Close.

取消单击按钮时,ShowDialog应返回false,这也要求设置DialogResult属性。When the Cancel button is clicked, ShowDialog should return false, which also requires setting the DialogResult property.

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

namespace SDKSample
{
    public partial class MarginsDialogBox : Window
    {
Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Input

Namespace SDKSample


Public Class MarginsDialogBox
    Inherits Window
void cancelButton_Click(object sender, RoutedEventArgs e)
{
    // Dialog box canceled
    this.DialogResult = false;
}
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自动设置为falseWhen a button's IsCancel property is set to true and the user presses either the Cancel button or the ESC key, DialogResult is automatically set to false. 以下标记具有相同的效果与上面的代码,而无需处理Click事件。The following markup has the same effect as the preceding code, without the need to handle the Click event.

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

对话框中会自动将返回false当用户按下关闭标题栏中按钮或选择关闭从菜单项系统菜单。A dialog box automatically returns false when a user presses the Close button in the title bar or chooses the Close menu item from the System menu.

处理从模式对话框返回的数据Processing Data Returned from a Modal Dialog Box

DialogResult设置通过对话框中,打开它的函数可以通过检查获取对话框结果DialogResult属性时ShowDialog返回。When DialogResult is set by a dialog box, the function that opened it can get the dialog box result by inspecting the DialogResult property when ShowDialog returns.

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

namespace SDKSample
{
    public partial class MainWindow : Window
    {

Imports System
Imports System.ComponentModel
Imports System.Windows
Imports System.Windows.Controls
Imports Microsoft.Win32

Namespace SDKSample

Public Class MainWindow
    Inherits Window
void formatMarginsMenuItem_Click(object sender, RoutedEventArgs e)
{
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 == true)
    {
        // Update fonts
        this.documentTextBox.Margin = dlg.DocumentMargin;
    }
}
    ' 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,该功能将其作为提示信息检索和处理由用户提供的数据。If the dialog result is true, the function uses that as a cue to retrieve and process the data provided by the user.

备注

ShowDialog已返回,无法重新打开一个对话框。After ShowDialog has returned, a dialog box cannot be reopened. 相反,需要创建新实例。Instead, you need to create a new instance.

如果对话框结果为false,该函数应结束适当地处理。If the dialog result is false, the function should end processing appropriately.

创建无模式自定义对话框Creating a Modeless Custom Dialog Box

无模式对话框(如下图中所示的“查找”对话框)与模式对话框具有相同的基本外观。A modeless dialog box, such as the Find Dialog Box shown in the following figure, has the same fundamental appearance as the modal dialog box.

“查找”对话框Find dialog box

但行为稍有不同,如以下各节中所述。However, the behavior is slightly different, as described in the following sections.

打开无模式对话框Opening a Modeless Dialog Box

无模式对话框打开通过调用Show方法。A modeless dialog box is opened by calling the Show method.

<!--Main Window-->
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;

namespace SDKSample
{
    public partial class MainWindow : Window
    {

Imports System
Imports System.ComponentModel
Imports System.Windows
Imports System.Windows.Controls
Imports Microsoft.Win32

Namespace SDKSample

Public Class MainWindow
    Inherits 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();
}
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

与不同ShowDialogShow立即返回。Unlike ShowDialog, Show returns immediately. 因此,调用窗口无法判断无模式对话框何时关闭,也就不知道何时检查对话框结果或从对话框获取数据进行进一步处理。Consequently, the calling window cannot tell when the modeless dialog box is closed and, therefore, does not know when to check for a dialog box result or get data from the dialog box for further processing. 相反,对话框需要创建替代方法来将数据返回到调用窗口进行处理。Instead, the dialog box needs to create an alternative way to return data to the calling window for processing.

处理无模式对话框返回的数据Processing Data Returned from a Modeless Dialog Box

在此示例中,FindDialogBox可能会返回一个或多个查找到主窗口中,具体取决于而无需任何特定的频率要搜索的文本的结果。In this example, the FindDialogBox may return one or more find results to the main window, depending on the text being searched for without any specific frequency. 和模式对话框一样,无模式对话框也可以使用属性返回结果。As with a modal dialog box, a modeless dialog box can return results using properties. 但拥有对话框的窗口需要了解何时检查那些属性。However, the window that owns the dialog box needs to know when to check those properties. 实现此目的的一种方法是用对话框实现事件,只要找到文本就引发它。One way to enable this is for the dialog box to implement an event that is raised whenever text is found. FindDialogBox 实现TextFoundEvent用于此目的,这首先需要委托。FindDialogBox implements the TextFoundEvent for this purpose, which first requires a delegate.

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实现TextFoundEventUsing the TextFoundEventHandler delegate, FindDialogBox implements the 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
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可以引发事件时找到搜索结果。Consequently, Find can raise the event when a search result is found.

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

namespace SDKSample
{
    public partial class FindDialogBox : Window
    {
Imports System
Imports System.Windows
Imports System.Windows.Controls
Imports System.Text.RegularExpressions

Namespace SDKSample

Public Class FindDialogBox
    Inherits Window
void findNextButton_Click(object sender, RoutedEventArgs e)
{
Private Sub findNextButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
// Text found
this.index = match.Index;
this.length = match.Length;
OnTextFound();
Me.Index = match.Index
Me.Length = match.Length
RaiseEvent TextFound(Me, EventArgs.Empty)
}
End Sub
    }
}
End Class

End Namespace

所有者窗口则需要注册和处理此事件。The owner window then needs to register with and handle this event.

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

namespace SDKSample
{
    public partial class MainWindow : Window
    {

Imports System
Imports System.ComponentModel
Imports System.Windows
Imports System.Windows.Controls
Imports Microsoft.Win32

Namespace SDKSample

Public Class MainWindow
    Inherits 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();
        }
    }
}
    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

关闭无模式对话框Closing a Modeless Dialog Box

因为DialogResult不需要是一组,可以关闭一个无模式对话框,使用系统提供的机制,其中包括:Because DialogResult does not need to be set, a modeless dialog can be closed using system provide mechanisms, including the following:

  • 单击关闭标题栏中的按钮。Clicking the Close button in the title bar.

  • 按 ALT+F4。Pressing ALT+F4.

  • 选择关闭系统菜单。Choosing Close from the System menu.

或者,你的代码可以调用Close关闭单击按钮。Alternatively, your code can call Close when the Close button is clicked.

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

namespace SDKSample
{
    public partial class FindDialogBox : Window
    {
Imports System
Imports System.Windows
Imports System.Windows.Controls
Imports System.Text.RegularExpressions

Namespace SDKSample

Public Class FindDialogBox
    Inherits Window
        void closeButton_Click(object sender, RoutedEventArgs e)
        {
            // Close dialog box
            this.Close();
        }
    }
}
    Private Sub closeButton_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
        MyBase.Close()
    End Sub
End Class

End Namespace

请参阅See Also

Popup 概述Popup Overview
对话框示例Dialog Box Sample
ColorPicker 自定义控件示例ColorPicker Custom Control Sample