对话框概述

独立应用程序通常具有显示应用程序通过其运行的主数据和通过用户界面 (UI) 机制公开功能来处理数据的主窗口,如菜单栏、工具栏和状态栏。 重要的应用程序可能还会显示其他窗口来执行以下操作:

  • 向用户显示特定信息。

  • 从用户处收集信息。

  • 同时显示并收集信息。

这些类型的窗口被称为“对话框”,它们有两种类型:模式和无模式

模式对话框由函数在其需要用户提供其他数据才能继续执行时显示。 由于函数依赖于模式对话框收集数据,模式对话框还会在其保持打开状态时防止用户激活应用程序中的其他窗口。 在大多数情况下,模式对话框使用户可以在完成操作时通过按“确定”或“取消”按钮来向模式对话框发信号。 按“确定”按钮表示用户已输入数据,希望函数继续处理该数据。 按“取消”按钮表示用户希望函数完全停止执行。 最常见的模式对话框示例显示为可以打开、保存并打印数据。

另一方面,无模式对话框则不会在其打开时防止用户激活其他窗口。 例如,如果用户想要在某个文档中查找特定字的出现次数,主窗口通常会打开一个对话框,询问用户要查找的字是什么。 查找字并不会防止用户编辑文档,因此对话框无需为模式对话框。 无模式对话框至少提供用于关闭对话框的“关闭”按钮,还可能提供执行特定函数的其他按钮,比如“查找下一个”按钮,用于查找符合字词搜索查找条件的下一个字词

利用 Windows Presentation Foundation (WPF),可以创建多种类型的对话框,包括消息框、通用对话框和自定义对话框。 本主题讨论各个对话框,对话框示例提供所匹配的示例。

消息框

消息框是可以用来显示文本信息并使用户可以使用按钮做出决定的对话框。 下图显示的消息框显示文本信息、提出问题并向用户提供了三个按钮来回答问题。

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

要创建消息框,可以使用 MessageBox 类。 MessageBox 让你可以使用与下面类似的代码来配置消息框文本、标题、图标和按钮。

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

要显示消息框,可以调用 staticShow 方法,如以下代码中所示。

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

当显示消息框的代码需要检测并处理用户决定(按下了哪个按钮)时,该代码可以检查消息框的结果,如以下代码中所示。

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

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

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

有关使用消息框的详细信息,请参阅 MessageBox消息框示例Dialog Box 示例

尽管 MessageBox 可能提供比较简单的对话框用户体验,但使用 MessageBox 的优势在于它是唯一一种可以由在部分信任安全沙箱内运行的应用程序显示的窗口(请参阅安全性),例如 XAML 浏览器应用程序 (XBAP)。

大多数对话框显示和收集比消息框结果更复杂的数据,包括文本、选项(复选框)、互斥选项(单选按钮)和列表选项(列表框、组合框、下拉列表框)。 对于这些数据,Windows Presentation Foundation (WPF) 提供多个通用对话框并允许创建自定义对话框,不过只有以完全信任方式运行的应用程序才可使用这些对话框。

通用对话框

Windows 实现所有应用程序(包括用于打开文件、保存文件和打印的对话框)通用的各种可重用的对话框。 这些对话框由操作系统实现,因此可以在运行于该操作系统上的所有应用程序之间共享,这对用户体验的一致性很有帮助;当用户熟悉一个应用程序中操作系统所提供的对话框时,他们就无需再去了解如何在其他应用程序中使用该对话框。 由于这些对话框对所有应用程序可用并且有助于提供一致的用户体验,因此被称为“通用对话框”

Windows Presentation Foundation (WPF) 将打开文件、保存文件和打印通用对话框封装在一起,并将其公开为托管类以便在独立应用程序中使用。 本主题提供每个通用对话框的简要概述。

打开文件对话框

如下图中所示的打开文件对话框由文件打开功能用于检索要打开文件的名称。

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

常见的打开文件对话框作为 OpenFileDialog 类实现,并位于 Microsoft.Win32 命名空间中。 以下代码显示了如何创建、配置和显示打开文件对话框以及如何处理结果。

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

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

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

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

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

有关打开文件对话框的详细信息,请参阅 Microsoft.Win32.OpenFileDialog

注意

OpenFileDialog可以被以部分信任方式运行的应用程序用来安全地检索文件名(请参阅安全性)。

保存文件对话框

如下图中所示的保存文件对话框由文件保存功能用以检索要保存的文件的名称。

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

常见的保存文件对话框作为 SaveFileDialog 类实现,并位于 Microsoft.Win32 命名空间中。 以下代码显示了如何创建、配置和显示打开文件对话框以及如何处理结果。

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

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

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

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

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

有关保存文件对话框的详细信息,请参阅 Microsoft.Win32.SaveFileDialog

如下图中所示的打印对话框由打印功能用以选择和配置用户想要将数据打印到的打印机。

Screenshot that shows a Print dialog box.

常见的打印对话框作为 PrintDialog 类实现,并位于 System.Windows.Controls 命名空间中。 以下代码显示了如何创建、配置和显示打印对话框。

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

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

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

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

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

有关打印对话框的详细信息,请参阅 System.Windows.Controls.PrintDialog。 有关在 WPF 中打印的详细讨论,请参阅打印概述

自定义对话框

尽管通用对话框很有用并应尽可能使用,但它们并不支持特定于域的对话框的要求。 在这些情况下,就需要创建自己的对话框。 如我们所见,对话框是具有特殊行为的窗口。 Window 实现那些行为,因此可以使用 Window 创建自定义模式和无模式对话框。

创建模式自定义对话框

本主题显示如何使用 Window 创建典型的模式对话框实现并以 Margins 对话框为例(请参阅对话框示例)。 Margins 对话框如下图所示。

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

配置模式对话框

典型对话框的用户界面包括以下内容:

  • 收集所需数据要求的各种控件。

  • “确定”按钮,用户单击该按钮可以关闭对话框、返回函数并继续处理

  • “取消”按钮,用户单击该按钮可以关闭对话框并使函数停止进一步处理

  • 标题栏中的“关闭”按钮

  • 图标。

  • “最小化”、“最大化”和“还原”按钮

  • “系统”菜单,用于最小化、最大化、还原和关闭该对话框

  • 打开对话框的窗口上方和中间的位置。

  • 能够尽可能调整大小(以防对话框过小)并为用户提供合适的默认尺寸。 因此需要分别设置默认尺寸和最小尺寸。

  • 用作键盘快捷方式的 Esc 键,可使“取消”按钮按下。 通过将“取消”按钮的 IsCancel 属性设置为 true,可以实现此目的

  • 用作键盘快捷方式的 Enter 键(或回车键),可使“确定”按钮按下。 通过将“确定”按钮的 IsDefault 属性设置为 true,可以实现此目的

以下代码演示了这种配置。

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

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

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

Namespace SDKSample
    Public Class MarginsDialogBox
        Inherits Window

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

对话框用户体验还扩展到打开对话框的窗口菜单栏。 当菜单项运行需要用户通过对话框交互才能继续运行的函数时,函数的菜单项标题上会有一个省略号,如此处所示。

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

当菜单项运行的函数显示无需用户交互的对话框(如“关于”对话框)时,则不需要省略号。

打开模式对话框

对话框通常显示为用户选择菜单项来执行特定于域的函数的结果,比如在字处理器中设置文档边距。 将窗口显示为对话框类似于显示普通窗口,只是它需要其他特定于对话框的配置。 以下代码中显示了实例化、配置和打开对话框的整个过程。

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

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

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

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

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

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

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

此处代码将默认信息(当前边距)传递给对话框。 它还将 Window.Owner 属性设置为对显示对话框的窗口的引用。 通常情况下,始终应设置对话框的所有者,以便提供所有对话框通用的与窗口状态相关的行为(请参阅 WPF 窗口概述获取详细信息)。

注意

必须提供所有者以支持对话框的用户界面 (UI) 自动化(请参阅 UI 自动化概述)。

配置好对话框后,将通过调用 ShowDialog 方法来以模式显示。

验证用户提供的数据

当打开对话框并且用户提供所需数据时,对话框出于以下原因负责确保提供的数据有效:

  • 从安全角度,应该验证所有输入。

  • 从特定于域的角度,数据验证可以防止代码处理错误数据,这可能引发异常。

  • 从用户体验角度,对话框可以帮助用户显示他们输入的哪些数据无效。

  • 从性能角度,多层应用程序中的数据验证可以减少客户端和应用程序层之间的往返次数,尤其当应用程序由 Web 服务或基于服务器的数据库构成时。

要验证 WPF 中的绑定控件,需要定义验证规则并将其与绑定进行关联。 验证规则是派生自 ValidationRule 的自定义类。 以下示例显示验证规则 MarginValidationRule,它检查绑定值是否为 Double 并在指定范围内。

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 方法来实现,该方法验证数据并返回合适的 ValidationResult

要将验证规则与绑定控件进行关联,可以使用以下标记。

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

  <Grid>

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

关联验证规则后,WPF 就会在数据输入到绑定控件中时自动应用它。 当控件包含无效数据时,WPF 会在无效控件周围显示红色边框,如下图所示。

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

WPF 不会在用户输入有效数据之前限制其对无效控件的访问。 这对于对话框来说很好,无论数据是否有效用户都应该可以自由导航到对话框中的控件。 但这意味着用户可以输入无效数据并按“确定”按钮。 出于这一原因,当按下“确定”按钮时,代码还需要通过处理 Click 事件来验证对话框中的所有控件

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

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

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

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

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

Namespace SDKSample
    Public Class MarginsDialogBox
        Inherits Window

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

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

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

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

此代码枚举窗口上的所有依赖对象,如有任何对象无效(如 GetHasError 所返回)则无效控件获得焦点,IsValid 方法返回 false,窗口被视为无效。

一旦对话框有效,就可以安全关闭并返回。 作为返回过程的一部分,需要将结果返回到调用函数。

设置模式对话框结果

使用 ShowDialog 打开对话框基本上类似于调用方法:使用 ShowDialog 打开对话框的代码等待 ShowDialog 返回。 当 ShowDialog 返回时,调用它的代码需要根据用户按“确定”按钮还是“取消”按钮来决定继续还是停止处理。 要帮助做出决定,对话框需要将用户选择作为 ShowDialog 方法返回的 Boolean 值。

单击“确定”按钮时,ShowDialog 应该返回 true。 这是通过在单击“确定”按钮时设置对话框的 DialogResult 属性来实现的

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

namespace SDKSample
{
    public partial class MarginsDialogBox : Window
    {

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

Namespace SDKSample
    Public Class MarginsDialogBox
        Inherits Window

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

注意,设置 DialogResult 属性还会导致窗口自动关闭,这减少了显式调用 Close 的需求。

当单击“取消”按钮时,ShowDialog 应该返回 false,这也需要设置 DialogResult 属性

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

namespace SDKSample
{
    public partial class MarginsDialogBox : Window
    {

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

Namespace SDKSample
    Public Class MarginsDialogBox
        Inherits Window

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

当按钮的 IsCancel 属性设置为 true 且用户按“取消”按钮或 Esc 键时,DialogResult 自动设置为 false。 以下标记具有与前面代码相同的效果,无需处理 Click 事件。

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

用户按标题栏中的“关闭”按钮或从“系统”菜单选择“关闭”菜单项时,对话框自动返回 false

处理从模式对话框返回的数据

DialogResult 由对话框设置时,打开它的函数可以通过 ShowDialog 返回时检查 DialogResult 属性来获取对话框结果。

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

namespace SDKSample
{
    public partial class MainWindow : Window
    {

        void formatMarginsMenuItem_Click(object sender, RoutedEventArgs e)
        {

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

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

如果对话框结果为 true,函数会将其用作提示来检索和处理用户提供的数据。

注意

ShowDialog 返回后则无法重新打开对话框。 相反,需要创建新实例。

如果对话框结果为 false,函数应适当结束处理。

创建无模式自定义对话框

无模式对话框(如下图中所示的“查找”对话框)与模式对话框具有相同的基本外观。

Screenshot that shows a Find dialog box.

但行为稍有不同,如以下各节中所述。

打开无模式对话框

无模式对话框通过调用 Show 方法来打开。

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

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

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

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

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

ShowDialog 不同的是,Show 会立即返回。 因此,调用窗口无法判断无模式对话框何时关闭,也就不知道何时检查对话框结果或从对话框获取数据进行进一步处理。 相反,对话框需要创建替代方法来将数据返回到调用窗口进行处理。

处理无模式对话框返回的数据

在此示例中,FindDialogBox 可能会将一个或多个查找结果返回到主窗口,具体取决于不以任何特定频率搜索的文本。 和模式对话框一样,无模式对话框也可以使用属性返回结果。 但拥有对话框的窗口需要了解何时检查那些属性。 实现此目的的一种方法是用对话框实现事件,只要找到文本就引发它。 FindDialogBox 出于此目的实现 TextFoundEvent,这首先需要委托。

using System;

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

使用 TextFoundEventHandler 委托,FindDialogBox 实现 TextFoundEvent

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

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

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

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

Namespace SDKSample

    Public Class FindDialogBox
        Inherits Window

        Public Event TextFound As TextFoundEventHandler

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

    End Class
End Namespace

因此,Find 可以在找到搜索结果时引发事件。

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

namespace SDKSample
{
    public partial class FindDialogBox : Window
    {

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

Namespace SDKSample

    Public Class FindDialogBox
        Inherits Window



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

    End Class
End Namespace

所有者窗口则需要注册和处理此事件。

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

namespace SDKSample
{
    public partial class MainWindow : Window
    {

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

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

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

关闭无模式对话框

由于 DialogResult 不需要设置,因此可以使用系统提供的机制关闭无模式对话框,包括以下步骤:

  • 单击标题栏中的“关闭”按钮

  • 按 ALT+F4。

  • 从“系统”菜单选择“关闭”

或者,单击“关闭”按钮时,代码可以调用 Close

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

namespace SDKSample
{
    public partial class FindDialogBox : Window
    {

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

Namespace SDKSample

    Public Class FindDialogBox
        Inherits Window

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

另请参阅