Общие сведения о диалоговых окнах

Автономные приложения обычно имеют главное окно; оно отображает основные данные, с которыми работает приложение, и предоставляет функциональные возможности для обработки этих данных посредством механизмов user interface (UI), таких как панель меню, панель инструментов и строка состояния. Нетривиальное приложение может также отображать дополнительные окна, которые выполняют следующие задачи.

  • Отображение отдельных сведений для пользователей.

  • Сбор сведений от пользователей.

  • И отображение, и сбор сведений.

Существует два типа таких окон, известных как диалоговые окна: модальные и немодальные.

Модальное диалоговое окно отображается функцией, когда она требует дополнительные данные от пользователя для продолжения. Поскольку для сбора данных функция зависит от модального диалогового окна, оно также запрещает пользователю активацию других окон в приложении, пока остается открытым. В большинстве случаев, модальное диалоговое окно разрешает пользователю оповещать о завершении работы с ним с помощью кнопок ОК или Отмена. Нажатие ОК кнопки означает, что пользователь ввел данные и желает, чтобы функция продолжила обработку данных. Нажатие кнопки Отмена указывает, что пользователь хочет полностью остановить выполнение функции. Наиболее общими примерами модальных диалоговых окон является отображение открытия, сохранения и печати данных.

Немодальное диалоговое окно, наоборот, не запрещает пользователю активацию других окон, когда оно открыто. Например, если пользователь желает найти вхождения конкретного слова в документе, в главном окне обычно открывается диалоговое окно с запросом слова для поиска. Поскольку поиск слова не запрещает редактирование документа пользователем, диалоговому окну не требуется быть модальными. Немодальное диалоговое окно, как минимум, содержит кнопку Закрыть для закрытия диалогового окна и может предоставлять дополнительные кнопки для выполнения отдельных функций, например — кнопку Найти далее, чтобы найти следующее слово, которое соответствует критерию поиска.

Windows Presentation Foundation (WPF) позволяет создавать несколько типов диалоговых окон, включая окна сообщений, общие диалоговые окна и настраиваемые диалоговые окна. В данной теме рассматриваются все эти типы. Примеры см. в разделе Dialog Box Sample ("Пример диалогового окна").

В этом разделе содержатся следующие подразделы.

  • Окна сообщений
  • Общие диалоговые окна
  • Настраиваемые диалоговые окна
  • Связанные разделы

Окна сообщений

Окно сообщения является диалоговым окном, которое можно использовать для отображения текстовых сведений, а также чтобы разрешить пользователям принимать решения с помощью кнопок. На следующем рисунке показано окно сообщения, отображающее текстовые сведения, вопрос, и предоставляющее пользователю три кнопки для ответа на вопрос.

Диалоговое окно “Текстовый процессор”

Для создания окна сообщения используется класс 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 Sample ("Пример MessageBox") и Dialog Box Sample ("Пример диалогового окна").

Хотя класс MessageBox может предложить простое диалоговое окно, преимущество использования класса MessageBox состоит в том что, это окно является единственным типом окна, которое может быть отображено приложениями, которые запущены в режиме безопасности частичного доверия "песочница" (см. раздел Безопасность (WPF)), например — приложением XAML browser applications (XBAPs).

Большинство диалоговых окон отображают и собирают более сложные данные, чем результат окна сообщения, включая текст, флажки, взаимоисключающий выбор (переключатели) и выбор списка (поля со списком, поля с раскрывающимся списком). Для этого Windows Presentation Foundation (WPF) предоставляет несколько общих диалоговых окон и позволяет создавать пользовательские диалоговые окна, хотя их использование ограничено приложениями, выполняющимися с полным доверием.

Общие диалоговые окна

Windows реализует различные многократно используемые диалоговые окна, которые являются общими для всех приложений, включая диалоговые окна для открытия, сохранения и печати файлов. Поскольку эти диалоговые окна реализованы операционной системой, они могут совместно использоваться всеми приложениями, работающими в операционной системе, помогая пользователям последовательно с ними взаимодействовать; когда пользователи знакомы с использованием диалогового окна операционной системы в одном приложении, им не нужно учиться пользоваться этим диалоговым окном в других приложениях. Поскольку эти диалоговые окна доступны для всех приложений и обеспечивают пользователю последовательное взаимодействие с ними, они называются общими диалоговыми окнами.

Windows Presentation Foundation (WPF) инкапсулирует общие диалоговые окна открытия, сохранения и печати файла и предоставляет их, как управляемые классы для использования в самостоятельных приложениях. В данном разделе представлен краткий обзор каждого из этих диалоговых окон.

Диалоговое окно открытия файлов

Диалоговое окно открытия файлов, показанное на следующем рисунке, используется функциональными возможностями открытия файла, чтобы извлечь его имя.

Диалоговое окно “Открыть”

Общее диалоговое окно открытия файлов реализуется как класс OpenFileDialog и размещается в пространстве имен Microsoft.Win32. Следующий код показывает, как создать, настроить и отобразить данное диалоговое окно, а также порядок обработки результата.

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

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

' Process open file dialog box results
If result = True Then
    ' Open document
    Dim filename As String = dlg.FileName
End If
// Configure open file dialog box
Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".txt"; // Default file extension
dlg.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension

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

// Process open file dialog box results
if (result == true)
{
    // Open document
    string filename = dlg.FileName;
}

Дополнительные сведения о диалоговых окнах открытия файлов см. в разделе Microsoft.Win32.OpenFileDialog.

ПримечаниеПримечание

Класс OpenFileDialog может использоваться для безопасного извлечения имен файлов приложениями, выполняемыми в режиме частичного доверия (см. Безопасность (WPF)).

Диалоговое окно сохранения файлов

Диалоговое окно сохранения файлов, показанное на следующем рисунке, используется функциональными возможностями сохранения файла, чтобы извлечь его имя.

Диалоговое окно “Сохранить как”

Общее диалоговое окно сохранения файлов реализуется как класс SaveFileDialog и размещается в пространстве имен Microsoft.Win32. Следующий код показывает, как создать, настроить и отобразить данное диалоговое окно, а также порядок обработки результата.

' Configure save file dialog box
Dim dlg As New Microsoft.Win32.SaveFileDialog()
dlg.FileName = "Document" ' Default file name
dlg.DefaultExt = ".text" ' Default file extension
dlg.Filter = "Text documents (.txt)|*.txt" ' Filter files by extension

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

' Process save file dialog box results
If result = True Then
    ' Save document
    Dim filename As String = dlg.FileName
End If
// Configure save file dialog box
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".text"; // Default file extension
dlg.Filter = "Text documents (.txt)|*.txt"; // Filter files by extension

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

// Process save file dialog box results
if (result == true)
{
    // Save document
    string filename = dlg.FileName;
}

Дополнительные сведения о диалоговых окнах сохранения файлов см. в разделе Microsoft.Win32.SaveFileDialog.

Диалоговое окно печати

Диалоговое окно печати, показанное на следующем рисунке, используется функциональными возможностями печати для выбора и настройки принтера, на котором будут напечатаны данные.

Диалоговое окно “Печать”

Общее диалоговое окно печати реализуется как класс PrintDialog и размещается в пространстве имен System.Windows.Controls. Следующий код показывает, как создать, настроить и отобразить это диалоговое окно.

' Configure printer dialog box
Dim dlg As New PrintDialog()
dlg.PageRangeSelection = PageRangeSelection.AllPages
dlg.UserPageRangeEnabled = True

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

' Process save file dialog box results
If result = True Then
    ' Print document
End If
// Configure printer dialog box
System.Windows.Controls.PrintDialog dlg = new System.Windows.Controls.PrintDialog();
dlg.PageRangeSelection = PageRangeSelection.AllPages;
dlg.UserPageRangeEnabled = true;

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

// Process save file dialog box results
if (result == true)
{
    // Print document
}

Дополнительные сведения о диалоговом окне печати см. в разделе System.Windows.Controls.PrintDialog. Подробное описание печати в приложении WPF см. в разделе Общие сведения о печати.

Настраиваемые диалоговые окна

Хотя общие диалоговые окна полезны и должны, при возможности, использоваться, они не поддерживают требования для диалоговых окон отдельного домена. В таких случаях, необходимо создавать пользовательские диалоговые окна. Как мы увидим, диалоговое окно представляет собой окно с особым поведением. Это поведение реализуется объектом Window, и, следовательно, для создания настраиваемых модальных и немодальных диалоговых окон необходимо использовать Window.

Создание модального настраиваемого диалогового окна

В этом разделе демонстрируется метод использования Window для создания реализации типичного модального диалогового окна с примером в виде диалогового окна Margins (см. раздел Dialog Box Sample ("Пример диалогового окна")). Диалоговое окно Margins показано на следующем рисунке.

Диалоговое окно “Границы”

Настройка модального диалогового окна

Пользовательский интерфейс типичного диалогового окна включает следующие элементы.

  • Различные элементы управления, которые необходимы для сбора нужных данных.

  • Отображение кнопки ОК, которую пользователь нажимает, чтобы закрыть окно, вернуться к функции и продолжить обработку данных.

  • Отображение кнопки Отмена, которую пользователь нажимает, чтобы закрыть окно и остановить дальнейшую обработку функции.

  • Отображение кнопки Закрыть в строке заголовка.

  • Отображение значка.

  • Отображение кнопок Свернуть, Развернуть и Восстановить.

  • Отображение меню Система для свертывания, развертывания, восстановления и закрытия окна.

  • Открытие выше и в центре окна, в котором открыто диалоговое окно.

  • Диалоговое окно должно быть изменяемым, где это возможно, чтобы можно было увеличить слишком маленький размер диалогового окна, и предоставить пользователю удобный для работы масштаб окна по умолчанию.

  • Нажатие клавиши ESC следует настроить, как сочетание клавиш, которое соответствует нажатию кнопки Отмена. Это достигается установкой для свойства IsCancel кнопки Отмена значения true.

  • Нажатие клавиши ВВОД следует настроить как сочетание клавиш, которое вызывает нажатие кнопки ОК. Это достигается установкой для свойства 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) диалоговых окон (см. Общие сведения о модели автоматизации пользовательского интерфейса).

После настройки диалогового окна оно отображается как модальное вызовом метода ShowDialog.

Проверка данных, предоставленных пользователем

При открытии диалогового окна, когда пользователь предоставляет требуемые данные, диалоговое окно ответственно за проверку подлинности данных по следующим причинам.

  • С точки зрения безопасности, все входные данные должны быть проверены.

  • С точки зрения отдельного домена, проверка данных запрещает обработку кодом ошибочных данных, которые потенциально могли вызвать исключения.

  • С точки зрения взаимодействия с пользователем, диалоговое окно может помочь пользователям, отображая неправильно введенные ими данные.

  • С точки зрения производительности, проверка данных в многоуровневом приложении может уменьшить число циклов передачи данных между клиентом и уровнями приложения, особенно, если приложение состоит из веб-служб и серверных баз данных.

Чтобы проверить связанный элемент управления в приложении WPF, необходимо определить правило проверки и связать его с привязкой. Правило проверки является пользовательским классом, производным от класса ValidationRule. В следующем примере показано правило проверки MarginValidationRule, которое проверяет, что связанным значением является Double и что оно находится в пределах указанного диапазона.

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);
        }
    }
}

В данном коде логика правила проверки реализована путем переопределения метода Validate, который проверяет данные и возвращает соответствующий объект ValidationResult.

Чтобы связать правило проверки со связанным элементом управления, используйте следующую разметку:

<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 не ограничивает пользователя недопустимым элементом управления, пока не будут введены допустимые данные. Это нормальное поведение диалогового окна; у пользователя должна быть возможность свободно перемещаться между элементами управления в диалоговом окне, независимо от того, являются данные допустимыми или нет. Однако это означает, что пользователь может ввести недопустимые данные и нажать кнопку ОК. По этой причине код также должен проверить все элементы управления в диалоговом окне при нажатии кнопки ОK, обрабатывая событие 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 код, вызвавший его, должен принять решение, продолжить или остановить обработку, в зависимости от того, нажал пользователь кнопку ОК или Отмена. Для упрощения этого решения диалоговое окно должно вернуть выбор пользователя как значение Boolean, возвращаемое из метода ShowDialog.

При нажатии кнопки ОК метод 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 установлено диалоговым окном, функция, которая открыла его, может получить результат диалогового окна, проверив свойство DialogResult при возвращении метода ShowDialog.


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();
        }
    }
}

См. также

Основные понятия

Общие сведения о контекстном меню

Другие ресурсы

Dialog Box Sample

ColorPicker Custom Control Sample