Example. This is a Windows Forms program that uses a Form1_Load event handler. We show a MessageBox with the OK and Cancel buttons (seen in the screenshot). We use the MessageBox.Show method for this.
Then: We use a switch selection statement on the DialogResult enum local variable.
Text: We change the Text property based on what button was clicked in the MessageBox.
And: If the Enter key was pressed, the OK button is used. The output of this program depends on the button pressed by the user.
C# program that uses switch on DialogResult
using System;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
DialogResult
result = MessageBox.Show(«How are you?», «Hi»,
MessageBoxButtons.OKCancel);
switch (result)
{
case DialogResult.OK:
{
this.Text = «[OK]»;
break;
}
case DialogResult.Cancel:
{
this.Text = «[Cancel]»;
break;
}
}
}
}
}
-
Use the
Close()
Method to Close Form in C# -
Set the
DialogResult
Property in Windows Forms to Close Form in C# -
Use the
Application.Exit
Method to Exit the Application in C# -
Use the
Environment.Exit
Method to Exit the Application in C# -
Use the
Form.Hide()
Method to Hide Form in C# -
Use the
Form.Dispose()
Method to Dispose Form in C# -
Conclusion
Closing a form is a fundamental operation in C# application development. Whether you’re building a Windows Forms Application or a Windows Presentation Foundation (WPF) Application, understanding how to close a form correctly is crucial for maintaining your application’s integrity and user experience.
This tutorial will explore different methods for closing a form in C# and provide step-by-step explanations and working code examples for each method.
Use the Close()
Method to Close Form in C#
The most straightforward way to close a form in C# is by using the Close()
method. This method is inherited from the System.Windows.Forms.Form
class and is available for Windows Forms and WPF applications.
Inside Form1
, we have a button (closeButton
) that, when clicked, calls this.Close()
to close the form.
using System;
using System.Windows.Forms;
namespace close_form {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void closeButton_Click(object sender, EventArgs e) {
this.Close();
}
}
}
In the above code, we closed the form in our Windows Forms application that only consists of one form with the Close()
method in C#.
This method only closes a single form in our application. It can also close a single form in an application that consists of multiple forms.
Set the DialogResult
Property in Windows Forms to Close Form in C#
In Windows Forms applications, you can use the DialogResult
property to close a form and indicate a specific result to the caller. This is often used when the form acts as a dialog box or a modal form.
using System;
using System.Windows.Forms;
namespace DialogResultDemo {
public partial class MainForm : Form {
public MainForm() {
InitializeComponent();
}
private void okButton_Click(object sender, EventArgs e) {
this.DialogResult = DialogResult.OK; // Set the DialogResult
this.Close(); // Close the form
}
private void cancelButton_Click(object sender, EventArgs e) {
this.DialogResult = DialogResult.Cancel; // Set the DialogResult
this.Close(); // Close the form
}
}
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// Show the MainForm as a dialog
if (new MainForm().ShowDialog() == DialogResult.OK) {
MessageBox.Show("OK button clicked.");
} else {
MessageBox.Show("Cancel button clicked or form closed.");
}
}
}
}
In the above code, we create a Windows Forms application with a form named MainForm
containing two buttons (okButton
and cancelButton
). When the OK
or Cancel
button is clicked, we set the DialogResult
property accordingly and then call this.Close()
to close the form.
Use the Application.Exit
Method to Exit the Application in C#
The Application.Exit()
method is used to close the entire application in C#. This method informs all message loops to terminate execution and closes the application after all the message loops have terminated.
We can also use this method to close a form in a Windows Forms application if our application only consists of one form.
However, use this method with caution. It’s essential to make sure that it’s appropriate to exit the entire application at that point, as it can lead to unexpected behavior if other forms or processes need to be closed or cleaned up.
using System;
using System.Windows.Forms;
namespace close_form {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private void exitButton_Click(object sender, EventArgs e) {
Application.Exit();
}
}
}
In the above code, when the Exit
button is clicked, we call Application.Exit()
to exit the entire application.
The drawback with this method is that the Application.Exit()
method exits the whole application. So, if the application contains more than one form, all the forms will be closed.
Use the Environment.Exit
Method to Exit the Application in C#
While it’s possible to close an application by calling Environment.Exit(0)
, it is generally discouraged.
This method forcefully terminates the application without allowing it to clean up resources or execute finalizers. It should only be used as a last resort when dealing with unhandled exceptions or critical issues.
using System;
using System.Windows.Forms;
namespace EnvironmentExitDemo {
public partial class MainForm : Form {
public MainForm() {
InitializeComponent();
}
private void exitButton_Click(object sender, EventArgs e) {
Environment.Exit(0); // Forcefully exit the entire application
}
}
}
In the above code, when the Exit
button is clicked, we call Environment.Exit(0)
to forcefully exit the entire application. This should be used sparingly, as it does not allow proper cleanup.
Application.Exit()
is specific to Windows Forms applications and provides a controlled, graceful exit, while Environment.Exit()
is a general-purpose method that forcibly terminates the application without any cleanup or event handling.
Use the Form.Hide()
Method to Hide Form in C#
Sometimes, you want to hide the form instead of closing it; you can use the Form.Hide()
method to do this. The form remains in memory and can be shown again using this.Show()
or this.Visible = true;
.
using System;
using System.Windows.Forms;
namespace FormHideDemo {
public partial class MainForm : Form {
public MainForm() {
InitializeComponent();
}
private void hideButton_Click(object sender, EventArgs e) {
this.Hide(); // Hide the form
}
private void showButton_Click(object sender, EventArgs e) {
this.Show(); // Show the hidden form
}
}
}
In the above code, we create a Windows Forms application with a form named MainForm
containing two buttons (hideButton
and showButton
).
When clicking the Hide
button, we call this.Hide()
to hide the form. When clicking the Show
button, we call this.Show()
to show the hidden form.
Use the Form.Dispose()
Method to Dispose Form in C#
You can explicitly dispose of a form and release its resources using the Form.Dispose()
method. It should be used when you explicitly want to release resources associated with the form, but it does not close its window.
using System;
using System.Windows.Forms;
namespace FormDisposeDemo {
public partial class MainForm : Form {
public MainForm() {
InitializeComponent();
}
private void disposeButton_Click(object sender, EventArgs e) {
this.Dispose(); // Dispose of the form
}
}
}
In the above code, when clicking the Dispose
button, we call this.Dispose()
to explicitly dispose of the form. This should be used when you want to release resources associated with the form.
Conclusion
Closing a form in C# involves several methods and considerations, depending on your application’s requirements. We have explored various methods, including using the Close()
method, setting the DialogResult
property, exiting the application, hiding the form, and disposing of the form.
Choosing the right method depends on your specific use case. Understanding when and how to use each method is crucial to ensure your application behaves as expected and provides a seamless user experience.
By mastering form closure techniques in C#, you can develop robust and user-friendly applications that meet the needs of your users while maintaining code integrity and resource management.
Enjoying our tutorials? Subscribe to DelftStack on YouTube to support us in creating more high-quality video guides. Subscribe
Диалоговые окна
Последнее обновление: 21.03.2016
WPF поддерживает возможность создания модальных диалоговых окон. При вызове модальное окно блокирует доступ к родительскому окну, пока пользователь
не закроет модальное окно.
Для работы добавим в проект новое окно, которое назовем PasswordWindow. Это окно будет выполнять роль модального.
Изменим интерфейс PasswordWindow:
<Window x:Class="WindowApp.PasswordWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WindowApp" mc:Ignorable="d" Title="Авторизация" SizeToContent="WidthAndHeight" WindowStartupLocation="CenterScreen"> <Grid Margin="10"> <Grid.RowDefinitions> <RowDefinition Height="20" /> <RowDefinition Height="20" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <TextBlock>Введите пароль:</TextBlock> <TextBox Name="passwordBox" Grid.Row="1" MinWidth="250">Пароль</TextBox> <WrapPanel Grid.Row="2" HorizontalAlignment="Right" Margin="0,15,0,0"> <Button IsDefault="True" Click="Accept_Click" MinWidth="60" Margin="0,0,10,0">OK</Button> <Button IsCancel="True" MinWidth="60">Отмена</Button> </WrapPanel> </Grid> </Window>
Здесь определено текстовое поле для ввода пароля и две кнопки. Вторая кнопка с атрибутом IsCancel="True"
будет выполнять роль отмены.
А первая кнопка будет подтверждать ввод.
Для подтверждения ввода и успешного выхода из модального окна определим в файле кода PasswordWindow определим обработчик первой кнопки Accept_Click:
using System.Windows; namespace WindowApp { public partial class PasswordWindow : Window { public PasswordWindow() { InitializeComponent(); } private void Accept_Click(object sender, RoutedEventArgs e) { this.DialogResult = true; } public string Password { get { return passwordBox.Text; } } } }
Для успешного выхода из модального диалогового окна нам надо для свойства DialogResult установить значение true
. Для
второй кнопки необязательно определять обработчик, так как у нее установлен атрибут IsCancel="True"
, следовательно, ее нажатие будет эквивалентно
результату this.DialogResult = false;
. Этот же результат будет при закрытии диалогового окна на крестик.
Кроме того, здесь определяется свойство Password
, через которое мы можем извне получить введенный пароль.
И изменим главную форму MainWindow, чтобы из нее запускать диалоговое окно. Во-первых, определим кнопку:
<Window x:Class="WindowApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WindowApp" mc:Ignorable="d" Title="MainWindow" Height="250" Width="300"> <Grid> <Button Width="100" Height="30" Content="Авторизация" Click="Login_Click" /> </Grid> </Window>
И определим обработчик для этой кнопки:
private void Login_Click(object sender, RoutedEventArgs e) { PasswordWindow passwordWindow = new PasswordWindow(); if(passwordWindow.ShowDialog()==true) { if(passwordWindow.Password=="12345678") MessageBox.Show("Авторизация пройдена"); else MessageBox.Show("Неверный пароль"); } else { MessageBox.Show("Авторизация не пройдена"); } }
В итоге при нажатии на кнопку будет отображаться следующее диалоговое окно:
И в зависимости от результатов ввода будет отображаться то или иное сообщение.
Общие сведения о диалоговых окнах
Автономные приложения обычно имеют главное окно, отображающее основные данные, с которыми приложение работает, и предоставляющее функциональные возможности для обработки этих данных через такие механизмы UI, как строки меню, панели инструментов и строки состояния. Нетривиальное приложение может также отображать дополнительные окна для следующих целей:
-
отображения определенных сведений для пользователей;
-
сбора сведений от пользователей;
-
одновременно сбора и отображения сведений.
Такие типы окон называются диалоговыми окнами, и бывают двух типов: модальные и немодальные.
Модальное диалоговое окно отображается функцией, когда для продолжения ей требуются дополнительные данные от пользователя. Поскольку функция зависит от модального диалогового окна для сбора данных, это окно также не разрешает пользователю активизировать другие окна в приложении, пока оно остается открытым. В большинстве случаев модальное диалоговое окно разрешает пользователю завершить работу с модальным диалоговым окном, нажав кнопки ОК или Отмена. Нажатие кнопки ОК обозначает, что пользователь ввел данные и желает, чтобы функция продолжила работу с этими данными. Нажатие кнопки Отмена обозначает, что пользователь хочет остановить выполнение функции. Наиболее распространенными примерами модальных диалоговых окон являются окна, которые отображаются для открытия, сохранения и печати данных.
Немодальное диалоговое окно, с другой стороны, не запрещает пользователю активацию других окон, когда оно открыто. Например, если пользователь хочет найти вхождения конкретного слова в документе, главное окно часто открывает диалоговое окно с запросом слова для поиска. Так как поиск слова не мешает пользователю редактировать документ, диалоговое окно не обязательно должно быть модальным. Немодальное диалоговое окно обычно содержит как минимум кнопку Закрыть и может предоставлять дополнительные кнопки для выполнения определенных функций, таких как Найти далее, чтобы найти следующее слово, соответствующее критерию поиска.
Windows Presentation Foundation (WPF) позволяет создавать несколько типов диалоговых окон, включая окна сообщений, общие диалоговые окна и пользовательские диалоговые окна. В этом разделе обсуждаются эти виды диалоговых окон, а в разделе примеры диалоговых окон приведены соответствующие примеры.
Окна сообщений
Окно сообщения является диалоговым окном, которое может использоваться для отображения текстовых данных и позволяет пользователям принимать решения с помощью кнопок. На следующем рисунке показано окно сообщения, в котором отображается текстовая информация, задается вопрос и предоставляются три кнопки для ответа на этот вопрос.
Для создания окна сообщения используйте класс 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;
Чтобы отобразить окно сообщения, вызовите static
метод Show, как показано в следующем коде.
// 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;
}
Дополнительные сведения об использовании окон сообщений см. в разделах MessageBox, пример MessageBox и примеры диалоговых окон.
Несмотря на то, что MessageBox предлагает лишь достаточно ограниченный пользовательский интерфейс диалогового окна, преимуществом использования MessageBox является то, что это единственный тип окна, который могут отображать приложения, работающие в песочнице с частичным доверием (см. в разделе безопасности), такие как XAML-приложения браузера (XBAP).
Большинство диалоговых окон отображают и собирают более сложные данные, чем результат окна сообщения, в том числе текст, выбранные варианты (флажки), взаимоисключающий выбор (переключатели) и списки выбора (списки, поля со списком, поля с раскрывающимся списком). Для этого Windows Presentation Foundation (WPF) предоставляет несколько общих диалоговых окон и позволяет создавать пользовательские диалоговые окна, хотя их использование возможно только для приложений, выполняемых с полным доверием.
Общие диалоговые окна
Windows реализует различные часто используемые диалоговые окна, которые являются общими для всех приложений, включая диалоговые окна для открытия и сохранения файлов, а также печати. Поскольку эти диалоговые окна реализованы операционной системой, они могут совместно использоваться всеми приложениями, работающими в операционной системе, что помогает поддерживать единообразие пользовательского интерфейса; если пользователи знакомы с диалоговым окном, предоставляемым операционной системой в одном приложении, им не нужно учиться пользоваться этим диалоговым окном в других приложениях. Поскольку эти диалоговые доступны для всех приложений и обеспечивают согласованный пользовательский интерфейс, они называются общими.
Windows Presentation Foundation (WPF) инкапсулирует диалоговые окна открытия файла, сохранения файла и печати и предоставляет их как управляемые классы для использования в автономных приложениях. В этом разделе приводится краткий обзор каждого типа диалоговых окон.
Диалоговое окно открытия файлов
Диалоговое окно открытия файлов, показанное на следующем рисунке, используется функцией открытия файла для получения имени открываемого файла.
Общее диалоговое окно открытия файла реализуется как класс 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;
}
Дополнительные сведения о диалоговом окне открытия файла см. в разделе Microsoft.Win32.OpenFileDialog.
Note
OpenFileDialog может использоваться для безопасного извлечения имен файлов приложениями, выполняющимися с частичным доверием (см. в разделе безопасность).
Диалоговое окно сохранения файлов
Диалоговое окно сохранения файлов, показанное на следующем рисунке, используется функцией сохранения файла для получения имени сохраняемого файла.
Общее диалоговое окно сохранения файла реализуется как класс 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;
}
Дополнительные сведения о диалоговом окне сохранения файла см. в разделе Microsoft.Win32.SaveFileDialog.
Диалоговое окно печати
Диалоговое окно печати, показанное на следующем рисунке, используется функциональными возможностями печати для выбора и настройки принтера, на котором пользователь хочет печатать данные.
Общее диалоговое окно печати реализуется как класс 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
}
Дополнительные сведения о диалоговом окне печати см. в разделе System.Windows.Controls.PrintDialog. Подробное описание печати в WPF см. в разделе Обзор печати.
Пользовательские диалоговые окна
Хотя общие диалоговые окна полезны и должны использоваться, когда это возможно, они не поддерживают требований диалоговых окон, относящихся к особой предметной области. В этих случаях необходимо создавать собственные диалоговые окна. Как мы увидим, диалоговое окно является окном со специальным поведением. Это поведение реализуется Window и, следовательно, для создания пользовательских модальных и немодальных диалоговых окон используется класс Window.
Создание модального пользовательского диалогового окна
В этом разделе показано, как использовать Window для реализации типичного модального диалогового окнп, используя диалоговое окно Margins
в качестве примера (см. в разделе примеры диалоговых окон). На следующем рисунке показано диалоговое окно Margins
.
Настройка модального диалогового окна
Пользовательский интерфейс для типичного диалогового окна включает следующее.
-
Различные элементы управления, которые необходимы для сбора нужных данных.
-
Кнопка ОК, чтобы закрыть диалоговое окно и вернуться в функцию для продолжения обработки.
-
Кнопка Отмена, чтобы закрыть диалоговое окно и остановить дальнейшую обработку функции.
-
Кнопка Закрыть в заголовке окна.
-
Значок.
-
Кнопки Свернуть, Развернуть и Восстановить.
-
Системное меню, которое позволяет свернуть, развернуть и закрыть окно.
-
Диалоговые окна должны быть регулируемого размера, где это возможно, и, чтобы предотвратить появление окна слишком малого размера, необходимо установить минимальные размеры окна и размеры по умолчанию.
-
Нажатие клавиши ESC следует настроить как сочетание клавиш, которое вызывает нажатие кнопки Отмена. Это достигается путем установки свойства IsCancel кнопки Отмена равным значению
true
. -
Нажатие клавиши ВВОД (RETURN) следует настроить как сочетание клавиш, которое вызывает нажатие кнопки ОК. Это достигается путем установки свойства 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>
<Grid.Resources>
<Style TargetType="{x:Type Grid}">
<Setter Property="Margin" Value="10" />
</Style>
<Style TargetType="{x:Type Label}">
<Setter Property="Margin" Value="0,3,5,5" />
<Setter Property="Padding" Value="0,0,0,5" />
</Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="0,0,0,5" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type StackPanel}">
<Setter Property="Orientation" Value="Horizontal" />
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Width" Value="70" />
<Setter Property="Height" Value="25" />
<Setter Property="Margin" Value="5,0,0,0" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!-- 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>
<!-- Top Margin -->
<Label Grid.Column="0" Grid.Row="1">Top Margin:</Label>
<TextBox Name="topMarginTextBox" Grid.Column="1" Grid.Row="1">
<TextBox.Text>
<Binding Path="Top" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:MarginValidationRule MinMargin="0" MaxMargin="10" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<!-- Right Margin -->
<Label Grid.Column="0" Grid.Row="2">Right Margin:</Label>
<TextBox Name="rightMarginTextBox" Grid.Column="1" Grid.Row="2">
<TextBox.Text>
<Binding Path="Right" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:MarginValidationRule MinMargin="0" MaxMargin="10" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<!-- Bottom Margin -->
<Label Grid.Column="0" Grid.Row="3">Bottom Margin:</Label>
<TextBox Name="bottomMarginTextBox" Grid.Column="1" Grid.Row="3">
<TextBox.Text>
<Binding Path="Bottom" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:MarginValidationRule MinMargin="0" MaxMargin="10" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<!-- 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();
}
public Thickness DocumentMargin
{
get { return (Thickness)this.DataContext; }
set { this.DataContext = value; }
}
void cancelButton_Click(object sender, RoutedEventArgs e)
{
// Dialog box canceled
this.DialogResult = false;
}
void okButton_Click(object sender, RoutedEventArgs e)
{
// Don't accept the dialog box if there is invalid data
if (!IsValid(this)) return;
// Dialog box accepted
this.DialogResult = true;
}
// 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;
}
}
}
Пользовательский интерфейс для диалогового окна также распространяется на строку меню окна, открывающего диалоговое окно. Если пункт меню вызывает функцию, которая перед продолжением выполнения требует взаимодействия с пользователем посредством диалогового окна, то в названии этого пункта меню должно быть многоточие, как показано ниже.
<Window
x:Class="SDKSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Document Window"
Height="300"
Width="350"
ResizeMode="CanResizeWithGrip"
Closing="mainWindow_Closing"
>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="_Open" Click="fileOpen_Click" />
<MenuItem Header="_Save" Click="fileSave_Click" />
<MenuItem Header="_Print" Click="filePrint_Click" />
<Separator />
<MenuItem Header="_Exit" Click="fileExit_Click" />
</MenuItem>
<MenuItem Header="_Edit">
<!--Main Window-->
<MenuItem Name="editFindMenuItem" Header="_Find" InputGestureText="Ctrl+F" Click="editFindMenuItem_Click" />
</MenuItem>
<MenuItem Header="F_ormat">
<MenuItem Name="formatFontMenuItem" Header="_Font..." Click="formatFontMenuItem_Click" />
<!--Main Window-->
<MenuItem Name="formatMarginsMenuItem" Header="_Margins..." Click="formatMarginsMenuItem_Click" />
</MenuItem>
</Menu>
<TextBox
Name="documentTextBox"
TextChanged="documentTextBox_TextChanged"
ScrollViewer.CanContentScroll="True"
ScrollViewer.HorizontalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollBarVisibility="Visible"
AcceptsReturn="True"
AcceptsTab="True"
BorderThickness="0" >
The quick brown fox jumps over the lazy old brown dog.
</TextBox>
</DockPanel>
</Window>
Если пункт меню вызывает функцию, которая отображает диалоговое окно, не требующее взаимодействия с пользователем, например диалоговое окно «О программе», многоточие не требуется.
Открытие модального диалогового окна
Диалоговое окно обычно отображается в результате выбора пользователем пункта меню для выполнения функции предметной области, такой как установка полей документа в текстовом редакторе. Отображение диалогового окна похоже на отображение обычного окна, хотя для диалогового окна требуется дополнительная настройка. Весь процесс создания, настройки и открытия диалогового окна показан в следующем коде.
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;
namespace SDKSample
{
public partial class MainWindow : Window
{
bool needsToBeSaved;
public MainWindow()
{
InitializeComponent();
}
// Closing
void mainWindow_Closing(object sender, CancelEventArgs e)
{
// If the document needs to be saved
if (this.needsToBeSaved)
{
// Configure the message box
string messageBoxText = "This document needs to be saved. Click Yes to save and exit, No to exit without saving, or Cancel to not exit.";
string caption = "Word Processor";
MessageBoxButton button = MessageBoxButton.YesNoCancel;
MessageBoxImage icon = MessageBoxImage.Warning;
// Display message box
MessageBoxResult messageBoxResult = MessageBox.Show(messageBoxText, caption, button, icon);
// Process message box results
switch (messageBoxResult)
{
case MessageBoxResult.Yes: // Save document and exit
SaveDocument();
break;
case MessageBoxResult.No: // Exit without saving
break;
case MessageBoxResult.Cancel: // Don't exit
e.Cancel = true;
break;
}
}
}
void fileOpen_Click(object sender, RoutedEventArgs e)
{
OpenDocument();
}
void fileSave_Click(object sender, RoutedEventArgs e)
{
SaveDocument();
}
void filePrint_Click(object sender, RoutedEventArgs e)
{
PrintDocument();
}
void fileExit_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
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();
}
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();
// Process data entered by user if dialog box is accepted
if (dlg.DialogResult == true)
{
// Update fonts
this.documentTextBox.Margin = dlg.DocumentMargin;
}
}
void formatFontMenuItem_Click(object sender, RoutedEventArgs e)
{
// Instantiate the dialog box
FontDialogBox dlg = new FontDialogBox();
// Configure the dialog box
dlg.Owner = this;
dlg.FontFamily = this.documentTextBox.FontFamily;
dlg.FontSize = this.documentTextBox.FontSize;
dlg.FontWeight = this.documentTextBox.FontWeight;
dlg.FontStyle = this.documentTextBox.FontStyle;
// Open the dialog box modally
dlg.ShowDialog();
// Process data entered by user if dialog box is accepted
if (dlg.DialogResult == true)
{
// Update fonts
this.documentTextBox.FontFamily = dlg.FontFamily;
this.documentTextBox.FontSize = dlg.FontSize;
this.documentTextBox.FontWeight = dlg.FontWeight;
this.documentTextBox.FontStyle = dlg.FontStyle;
}
}
// Detect when document has been altered
void documentTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
this.needsToBeSaved = true;
}
void OpenDocument()
{
// Instantiate the dialog box
OpenFileDialog dlg = new OpenFileDialog();
// Configure open file dialog box
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".wpf"; // Default file extension
dlg.Filter = "Word Processor Files (.wpf)|*.wpf"; // Filter files by extension
// Open the dialog box modally
Nullable<bool> result = dlg.ShowDialog();
// Process open file dialog box results
if (result == true)
{
// Open document
string filename = dlg.FileName;
}
}
void SaveDocument()
{
// Configure save file dialog
SaveFileDialog dlg = new SaveFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".wpf"; // Default file extension
dlg.Filter = "Word Processor Files (.wpf)|*.wpf"; // Filter files by extension
// Show save file dialog
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog results
if (result == true)
{
// Save document
string filename = dlg.FileName;
}
}
void PrintDocument()
{
// Configure printer dialog
PrintDialog dlg = new PrintDialog();
dlg.PageRangeSelection = PageRangeSelection.AllPages;
dlg.UserPageRangeEnabled = true;
// Show save file dialog
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog results
if (result == true)
{
// Print document
}
}
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();
}
}
}
Здесь код передает в диалоговое окно сведения по умолчанию (о текущих полях). Он также присваивает свойству Window.Owner ссылку на окно, которое отображает диалоговое окно. Как правило, следует всегда устанавливать владельца для диалогового окна, чтобы задать поведения, связанные с состоянием окна, которые являются общими для всех диалоговых окон (подробнее см. в разделе Общие сведения об окнах WPF).
После настройки диалогового окна, его можно отобразить как модальное путем вызова ShowDialog.
Проверка пользовательских данных
Если открывается диалоговое окно и пользователь предоставляет требуемые данные, диалоговое окно отвечает за проверку допустимости предоставленных данных по следующим причинам.
-
С точки зрения безопасности, следует проверять все входные данные.
-
С точки зрения конкретной предметной области, следует предотвращать обработку ошибочных данных, которые могут вызывать исключения.
-
С точки зрения взаимодействия с пользователем, диалоговое окно может помочь пользователям, показывая, какие введенные ими данные являются недопустимыми.
-
С точки зрения производительности, проверка данных в многоуровневом приложении может уменьшить количество циклов обработки между уровнями клиента и приложения, особенно в том случае, если в приложение входят веб-службы или серверные базы данных.
Чтобы проверить связанный элемент управления в WPF, необходимо определить правило проверки и связать его с привязкой. Правило проверки — пользовательский класс, производный от ValidationRule. В следующем примере показано правило проверки, MarginValidationRule
, которое проверяет, что связанное значение имеет тип Double и находится в пределах указанного диапазона.
В этом коде логика правила проверки реализована путем переопределения 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>
<Grid.Resources>
<Style TargetType="{x:Type Grid}">
<Setter Property="Margin" Value="10" />
</Style>
<Style TargetType="{x:Type Label}">
<Setter Property="Margin" Value="0,3,5,5" />
<Setter Property="Padding" Value="0,0,0,5" />
</Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="0,0,0,5" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type StackPanel}">
<Setter Property="Orientation" Value="Horizontal" />
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Width" Value="70" />
<Setter Property="Height" Value="25" />
<Setter Property="Margin" Value="5,0,0,0" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!-- 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>
<!-- Top Margin -->
<Label Grid.Column="0" Grid.Row="1">Top Margin:</Label>
<TextBox Name="topMarginTextBox" Grid.Column="1" Grid.Row="1">
<TextBox.Text>
<Binding Path="Top" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:MarginValidationRule MinMargin="0" MaxMargin="10" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<!-- Right Margin -->
<Label Grid.Column="0" Grid.Row="2">Right Margin:</Label>
<TextBox Name="rightMarginTextBox" Grid.Column="1" Grid.Row="2">
<TextBox.Text>
<Binding Path="Right" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:MarginValidationRule MinMargin="0" MaxMargin="10" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<!-- Bottom Margin -->
<Label Grid.Column="0" Grid.Row="3">Bottom Margin:</Label>
<TextBox Name="bottomMarginTextBox" Grid.Column="1" Grid.Row="3">
<TextBox.Text>
<Binding Path="Bottom" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:MarginValidationRule MinMargin="0" MaxMargin="10" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<!-- 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>
После связывания, правила проверки WPF автоматически применяются при вводе данных в связанном элементе управления. Если элемент управления содержит недопустимые данные, WPF отобразит красные границы вокруг недопустимого элемента, как показано на рисунке ниже.
WPF не ограничивает переход пользователя из элемента управления с недопустимым значением, пока не будут введены допустимые данные. Это правильное поведение диалогового окна; пользователь должен иметь возможность свободно перемещаться по элементам управления в диалоговом окне, независимо от того, правильны ли введенные данные. Тем не менее, это означает, что пользователь может ввести недопустимые данные и нажать кнопку ОК. По этой причине код также должен проверить все элементы управления в диалоговом окне при нажатии ОК путем обработки события Click.
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace SDKSample
{
public partial class MarginsDialogBox : Window
{
public MarginsDialogBox()
{
InitializeComponent();
}
public Thickness DocumentMargin
{
get { return (Thickness)this.DataContext; }
set { this.DataContext = value; }
}
void cancelButton_Click(object sender, RoutedEventArgs e)
{
// Dialog box canceled
this.DialogResult = false;
}
void okButton_Click(object sender, RoutedEventArgs e)
{
// Don't accept the dialog box if there is invalid data
if (!IsValid(this)) return;
// Dialog box accepted
this.DialogResult = true;
}
// 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 при нажатии кнопки ОК.
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace SDKSample
{
public partial class MarginsDialogBox : Window
{
public MarginsDialogBox()
{
InitializeComponent();
}
public Thickness DocumentMargin
{
get { return (Thickness)this.DataContext; }
set { this.DataContext = value; }
}
void cancelButton_Click(object sender, RoutedEventArgs e)
{
// Dialog box canceled
this.DialogResult = false;
}
void okButton_Click(object sender, RoutedEventArgs e)
{
// Don't accept the dialog box if there is invalid data
if (!IsValid(this)) return;
// Dialog box accepted
this.DialogResult = true;
}
// 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;
}
}
}
Обратите внимание, что DialogResult также вызывает автоматическое закрытие окна, что устраняет необходимость явно вызывать Close.
При нажатии Отмена, ShowDialog должен возвращать false
, что также требует установки DialogResult.
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace SDKSample
{
public partial class MarginsDialogBox : Window
{
public MarginsDialogBox()
{
InitializeComponent();
}
public Thickness DocumentMargin
{
get { return (Thickness)this.DataContext; }
set { this.DataContext = value; }
}
void cancelButton_Click(object sender, RoutedEventArgs e)
{
// Dialog box canceled
this.DialogResult = false;
}
void okButton_Click(object sender, RoutedEventArgs e)
{
// Don't accept the dialog box if there is invalid data
if (!IsValid(this)) return;
// Dialog box accepted
this.DialogResult = true;
}
// 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;
}
}
}
Когда IsCancel равно true
и пользователь нажимает кнопку Отмена или клавишу ESC, DialogResult автоматически присваивается false
. Следующая разметка действует так же, как предыдущий код, без необходимости обрабатывать событие Click.
<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>
<Grid.Resources>
<Style TargetType="{x:Type Grid}">
<Setter Property="Margin" Value="10" />
</Style>
<Style TargetType="{x:Type Label}">
<Setter Property="Margin" Value="0,3,5,5" />
<Setter Property="Padding" Value="0,0,0,5" />
</Style>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="0,0,0,5" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type StackPanel}">
<Setter Property="Orientation" Value="Horizontal" />
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Width" Value="70" />
<Setter Property="Height" Value="25" />
<Setter Property="Margin" Value="5,0,0,0" />
</Style>
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<!-- 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>
<!-- Top Margin -->
<Label Grid.Column="0" Grid.Row="1">Top Margin:</Label>
<TextBox Name="topMarginTextBox" Grid.Column="1" Grid.Row="1">
<TextBox.Text>
<Binding Path="Top" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:MarginValidationRule MinMargin="0" MaxMargin="10" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<!-- Right Margin -->
<Label Grid.Column="0" Grid.Row="2">Right Margin:</Label>
<TextBox Name="rightMarginTextBox" Grid.Column="1" Grid.Row="2">
<TextBox.Text>
<Binding Path="Right" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:MarginValidationRule MinMargin="0" MaxMargin="10" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<!-- Bottom Margin -->
<Label Grid.Column="0" Grid.Row="3">Bottom Margin:</Label>
<TextBox Name="bottomMarginTextBox" Grid.Column="1" Grid.Row="3">
<TextBox.Text>
<Binding Path="Bottom" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<local:MarginValidationRule MinMargin="0" MaxMargin="10" />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<!-- 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>
Диалоговое окно автоматически возвращает false
, когда пользователь нажимает кнопку Закрыть в строке заголовка или выбирает Закрыть в системном меню.
Обработка данных, возвращенных из модального диалогового окна
Когда DialogResult устанавливается диалоговым окном, функция, которая его открыла, может получить результат диалогового окна, проверив значение DialogResult, которое возвращает ShowDialog.
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;
namespace SDKSample
{
public partial class MainWindow : Window
{
bool needsToBeSaved;
public MainWindow()
{
InitializeComponent();
}
// Closing
void mainWindow_Closing(object sender, CancelEventArgs e)
{
// If the document needs to be saved
if (this.needsToBeSaved)
{
// Configure the message box
string messageBoxText = "This document needs to be saved. Click Yes to save and exit, No to exit without saving, or Cancel to not exit.";
string caption = "Word Processor";
MessageBoxButton button = MessageBoxButton.YesNoCancel;
MessageBoxImage icon = MessageBoxImage.Warning;
// Display message box
MessageBoxResult messageBoxResult = MessageBox.Show(messageBoxText, caption, button, icon);
// Process message box results
switch (messageBoxResult)
{
case MessageBoxResult.Yes: // Save document and exit
SaveDocument();
break;
case MessageBoxResult.No: // Exit without saving
break;
case MessageBoxResult.Cancel: // Don't exit
e.Cancel = true;
break;
}
}
}
void fileOpen_Click(object sender, RoutedEventArgs e)
{
OpenDocument();
}
void fileSave_Click(object sender, RoutedEventArgs e)
{
SaveDocument();
}
void filePrint_Click(object sender, RoutedEventArgs e)
{
PrintDocument();
}
void fileExit_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
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();
}
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();
// Process data entered by user if dialog box is accepted
if (dlg.DialogResult == true)
{
// Update fonts
this.documentTextBox.Margin = dlg.DocumentMargin;
}
}
void formatFontMenuItem_Click(object sender, RoutedEventArgs e)
{
// Instantiate the dialog box
FontDialogBox dlg = new FontDialogBox();
// Configure the dialog box
dlg.Owner = this;
dlg.FontFamily = this.documentTextBox.FontFamily;
dlg.FontSize = this.documentTextBox.FontSize;
dlg.FontWeight = this.documentTextBox.FontWeight;
dlg.FontStyle = this.documentTextBox.FontStyle;
// Open the dialog box modally
dlg.ShowDialog();
// Process data entered by user if dialog box is accepted
if (dlg.DialogResult == true)
{
// Update fonts
this.documentTextBox.FontFamily = dlg.FontFamily;
this.documentTextBox.FontSize = dlg.FontSize;
this.documentTextBox.FontWeight = dlg.FontWeight;
this.documentTextBox.FontStyle = dlg.FontStyle;
}
}
// Detect when document has been altered
void documentTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
this.needsToBeSaved = true;
}
void OpenDocument()
{
// Instantiate the dialog box
OpenFileDialog dlg = new OpenFileDialog();
// Configure open file dialog box
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".wpf"; // Default file extension
dlg.Filter = "Word Processor Files (.wpf)|*.wpf"; // Filter files by extension
// Open the dialog box modally
Nullable<bool> result = dlg.ShowDialog();
// Process open file dialog box results
if (result == true)
{
// Open document
string filename = dlg.FileName;
}
}
void SaveDocument()
{
// Configure save file dialog
SaveFileDialog dlg = new SaveFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".wpf"; // Default file extension
dlg.Filter = "Word Processor Files (.wpf)|*.wpf"; // Filter files by extension
// Show save file dialog
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog results
if (result == true)
{
// Save document
string filename = dlg.FileName;
}
}
void PrintDocument()
{
// Configure printer dialog
PrintDialog dlg = new PrintDialog();
dlg.PageRangeSelection = PageRangeSelection.AllPages;
dlg.UserPageRangeEnabled = true;
// Show save file dialog
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog results
if (result == true)
{
// Print document
}
}
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();
}
}
}
Если результатом диалогового окна является true
, функция использует его в качестве указания, что нужно получить и обработать данные, предоставленные пользователем.
Note
После возврата ShowDialog диалоговое окно нельзя открыть повторно. Вместо этого придется создать новый экземпляр.
Если результатом диалогового окна является false
, функция должна соответствующим образом завершить обработку.
Создание немодального пользовательского диалогового окна
Немодальное диалоговое окно, например диалоговое окно поиска, показанное на следующем рисунке, в основном имеет такой же внешний вид, как и модальное диалоговое окно.
Однако поведение несколько отличается, как показано в следующих разделах.
Открытие немодального диалогового окна
Немодальное диалоговое окно открывается путем вызова метода Show.
<Window
x:Class="SDKSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Document Window"
Height="300"
Width="350"
ResizeMode="CanResizeWithGrip"
Closing="mainWindow_Closing"
>
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="_Open" Click="fileOpen_Click" />
<MenuItem Header="_Save" Click="fileSave_Click" />
<MenuItem Header="_Print" Click="filePrint_Click" />
<Separator />
<MenuItem Header="_Exit" Click="fileExit_Click" />
</MenuItem>
<MenuItem Header="_Edit">
<!--Main Window-->
<MenuItem Name="editFindMenuItem" Header="_Find" InputGestureText="Ctrl+F" Click="editFindMenuItem_Click" />
</MenuItem>
<MenuItem Header="F_ormat">
<MenuItem Name="formatFontMenuItem" Header="_Font..." Click="formatFontMenuItem_Click" />
<!--Main Window-->
<MenuItem Name="formatMarginsMenuItem" Header="_Margins..." Click="formatMarginsMenuItem_Click" />
</MenuItem>
</Menu>
<TextBox
Name="documentTextBox"
TextChanged="documentTextBox_TextChanged"
ScrollViewer.CanContentScroll="True"
ScrollViewer.HorizontalScrollBarVisibility="Visible"
ScrollViewer.VerticalScrollBarVisibility="Visible"
AcceptsReturn="True"
AcceptsTab="True"
BorderThickness="0" >
The quick brown fox jumps over the lazy old brown dog.
</TextBox>
</DockPanel>
</Window>
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;
namespace SDKSample
{
public partial class MainWindow : Window
{
bool needsToBeSaved;
public MainWindow()
{
InitializeComponent();
}
// Closing
void mainWindow_Closing(object sender, CancelEventArgs e)
{
// If the document needs to be saved
if (this.needsToBeSaved)
{
// Configure the message box
string messageBoxText = "This document needs to be saved. Click Yes to save and exit, No to exit without saving, or Cancel to not exit.";
string caption = "Word Processor";
MessageBoxButton button = MessageBoxButton.YesNoCancel;
MessageBoxImage icon = MessageBoxImage.Warning;
// Display message box
MessageBoxResult messageBoxResult = MessageBox.Show(messageBoxText, caption, button, icon);
// Process message box results
switch (messageBoxResult)
{
case MessageBoxResult.Yes: // Save document and exit
SaveDocument();
break;
case MessageBoxResult.No: // Exit without saving
break;
case MessageBoxResult.Cancel: // Don't exit
e.Cancel = true;
break;
}
}
}
void fileOpen_Click(object sender, RoutedEventArgs e)
{
OpenDocument();
}
void fileSave_Click(object sender, RoutedEventArgs e)
{
SaveDocument();
}
void filePrint_Click(object sender, RoutedEventArgs e)
{
PrintDocument();
}
void fileExit_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
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();
}
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();
// Process data entered by user if dialog box is accepted
if (dlg.DialogResult == true)
{
// Update fonts
this.documentTextBox.Margin = dlg.DocumentMargin;
}
}
void formatFontMenuItem_Click(object sender, RoutedEventArgs e)
{
// Instantiate the dialog box
FontDialogBox dlg = new FontDialogBox();
// Configure the dialog box
dlg.Owner = this;
dlg.FontFamily = this.documentTextBox.FontFamily;
dlg.FontSize = this.documentTextBox.FontSize;
dlg.FontWeight = this.documentTextBox.FontWeight;
dlg.FontStyle = this.documentTextBox.FontStyle;
// Open the dialog box modally
dlg.ShowDialog();
// Process data entered by user if dialog box is accepted
if (dlg.DialogResult == true)
{
// Update fonts
this.documentTextBox.FontFamily = dlg.FontFamily;
this.documentTextBox.FontSize = dlg.FontSize;
this.documentTextBox.FontWeight = dlg.FontWeight;
this.documentTextBox.FontStyle = dlg.FontStyle;
}
}
// Detect when document has been altered
void documentTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
this.needsToBeSaved = true;
}
void OpenDocument()
{
// Instantiate the dialog box
OpenFileDialog dlg = new OpenFileDialog();
// Configure open file dialog box
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".wpf"; // Default file extension
dlg.Filter = "Word Processor Files (.wpf)|*.wpf"; // Filter files by extension
// Open the dialog box modally
Nullable<bool> result = dlg.ShowDialog();
// Process open file dialog box results
if (result == true)
{
// Open document
string filename = dlg.FileName;
}
}
void SaveDocument()
{
// Configure save file dialog
SaveFileDialog dlg = new SaveFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".wpf"; // Default file extension
dlg.Filter = "Word Processor Files (.wpf)|*.wpf"; // Filter files by extension
// Show save file dialog
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog results
if (result == true)
{
// Save document
string filename = dlg.FileName;
}
}
void PrintDocument()
{
// Configure printer dialog
PrintDialog dlg = new PrintDialog();
dlg.PageRangeSelection = PageRangeSelection.AllPages;
dlg.UserPageRangeEnabled = true;
// Show save file dialog
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog results
if (result == true)
{
// Print document
}
}
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();
}
}
}
В отличие от ShowDialog, Show возвращает немедленно. Следовательно, вызывающее окно не может определить, когда немодальное диалоговое окно закрывается, и поэтому не знает, когда следует проверить результат диалогового окна или получить данные из диалогового окна для дальнейшей обработки. Поэтому диалоговому окну необходимо создать альтернативный способ возврата данных в вызывающее окно для обработки.
Обработка данных, возвращенных из немодального диалогового окна
В этом примере FindDialogBox
может возвращать один или несколько результатов в главное окно в зависимости от искомого текста. Как и в случае с модальным диалоговым окном, немодальное диалоговое окно может возвращать результаты с помощью свойств. Однако окну, которому принадлежит данное диалоговое окно, нужно знать, когда следует проверять эти свойства. Один из способов сделать это — реализовать для диалогового окна событие, которое возникает всякий раз, когда текст найден. FindDialogBox
реализует для этой цели TextFoundEvent
.
using System;
namespace SDKSample
{
public delegate void TextFoundEventHandler(object sender, EventArgs e);
}
С помощью делегата 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);
}
public FindDialogBox(TextBox textBoxToSearch)
{
InitializeComponent();
this.textBoxToSearch = textBoxToSearch;
// If text box that's being searched is changed, reset search
this.textBoxToSearch.TextChanged += textBoxToSearch_TextChanged;
}
// Text to search
TextBox textBoxToSearch;
// Find results
MatchCollection matches;
int matchIndex = 0;
// Search results
int index = 0;
int length = 0;
public int Index
{
get { return this.index; }
set { this.index = value; }
}
public int Length
{
get { return this.length; }
set { this.length = value; }
}
void findNextButton_Click(object sender, RoutedEventArgs e)
{
// Find matches
if (this.matches == null)
{
string pattern = this.findWhatTextBox.Text;
// Match whole word?
if ((bool)this.matchWholeWordCheckBox.IsChecked) pattern = @"(?<=\W{0,1})" + pattern + @"(?=\W)";
// Case sensitive
if (!(bool)this.caseSensitiveCheckBox.IsChecked) pattern = "(?i)" + pattern;
// Find matches
this.matches = Regex.Matches(this.textBoxToSearch.Text, pattern);
this.matchIndex = 0;
// Word not found?
if (this.matches.Count == 0)
{
MessageBox.Show("'" + this.findWhatTextBox.Text + "' not found.", "Find");
this.matches = null;
return;
}
}
// Start at beginning of matches if the last find selected the last match
if (this.matchIndex == this.matches.Count)
{
MessageBoxResult result = MessageBox.Show("Nmore matches found. Start at beginning?", "Find", MessageBoxButton.YesNo);
if (result == MessageBoxResult.No) return;
// Reset
this.matchIndex = 0;
}
// Return match details to client so it can select the text
Match match = this.matches[this.matchIndex];
if (TextFound != null)
{
// Text found
this.index = match.Index;
this.length = match.Length;
OnTextFound();
}
this.matchIndex++;
}
void textBoxToSearch_TextChanged(object sender, TextChangedEventArgs e)
{
ResetFind();
}
void findWhatTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
ResetFind();
}
void criteria_Click(object sender, RoutedEventArgs e)
{
ResetFind();
}
void ResetFind()
{
this.findNextButton.IsEnabled = true;
this.matches = null;
}
void closeButton_Click(object sender, RoutedEventArgs e)
{
// Close dialog box
this.Close();
}
}
}
Следовательно, Find
может создать событие, когда найден результат поиска.
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);
}
public FindDialogBox(TextBox textBoxToSearch)
{
InitializeComponent();
this.textBoxToSearch = textBoxToSearch;
// If text box that's being searched is changed, reset search
this.textBoxToSearch.TextChanged += textBoxToSearch_TextChanged;
}
// Text to search
TextBox textBoxToSearch;
// Find results
MatchCollection matches;
int matchIndex = 0;
// Search results
int index = 0;
int length = 0;
public int Index
{
get { return this.index; }
set { this.index = value; }
}
public int Length
{
get { return this.length; }
set { this.length = value; }
}
void findNextButton_Click(object sender, RoutedEventArgs e)
{
// Find matches
if (this.matches == null)
{
string pattern = this.findWhatTextBox.Text;
// Match whole word?
if ((bool)this.matchWholeWordCheckBox.IsChecked) pattern = @"(?<=\W{0,1})" + pattern + @"(?=\W)";
// Case sensitive
if (!(bool)this.caseSensitiveCheckBox.IsChecked) pattern = "(?i)" + pattern;
// Find matches
this.matches = Regex.Matches(this.textBoxToSearch.Text, pattern);
this.matchIndex = 0;
// Word not found?
if (this.matches.Count == 0)
{
MessageBox.Show("'" + this.findWhatTextBox.Text + "' not found.", "Find");
this.matches = null;
return;
}
}
// Start at beginning of matches if the last find selected the last match
if (this.matchIndex == this.matches.Count)
{
MessageBoxResult result = MessageBox.Show("Nmore matches found. Start at beginning?", "Find", MessageBoxButton.YesNo);
if (result == MessageBoxResult.No) return;
// Reset
this.matchIndex = 0;
}
// Return match details to client so it can select the text
Match match = this.matches[this.matchIndex];
if (TextFound != null)
{
// Text found
this.index = match.Index;
this.length = match.Length;
OnTextFound();
}
this.matchIndex++;
}
void textBoxToSearch_TextChanged(object sender, TextChangedEventArgs e)
{
ResetFind();
}
void findWhatTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
ResetFind();
}
void criteria_Click(object sender, RoutedEventArgs e)
{
ResetFind();
}
void ResetFind()
{
this.findNextButton.IsEnabled = true;
this.matches = null;
}
void closeButton_Click(object sender, RoutedEventArgs e)
{
// Close dialog box
this.Close();
}
}
}
Затем окну-владельцу нужно зарегистрировать и обработать это событие.
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;
namespace SDKSample
{
public partial class MainWindow : Window
{
bool needsToBeSaved;
public MainWindow()
{
InitializeComponent();
}
// Closing
void mainWindow_Closing(object sender, CancelEventArgs e)
{
// If the document needs to be saved
if (this.needsToBeSaved)
{
// Configure the message box
string messageBoxText = "This document needs to be saved. Click Yes to save and exit, No to exit without saving, or Cancel to not exit.";
string caption = "Word Processor";
MessageBoxButton button = MessageBoxButton.YesNoCancel;
MessageBoxImage icon = MessageBoxImage.Warning;
// Display message box
MessageBoxResult messageBoxResult = MessageBox.Show(messageBoxText, caption, button, icon);
// Process message box results
switch (messageBoxResult)
{
case MessageBoxResult.Yes: // Save document and exit
SaveDocument();
break;
case MessageBoxResult.No: // Exit without saving
break;
case MessageBoxResult.Cancel: // Don't exit
e.Cancel = true;
break;
}
}
}
void fileOpen_Click(object sender, RoutedEventArgs e)
{
OpenDocument();
}
void fileSave_Click(object sender, RoutedEventArgs e)
{
SaveDocument();
}
void filePrint_Click(object sender, RoutedEventArgs e)
{
PrintDocument();
}
void fileExit_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
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();
}
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();
// Process data entered by user if dialog box is accepted
if (dlg.DialogResult == true)
{
// Update fonts
this.documentTextBox.Margin = dlg.DocumentMargin;
}
}
void formatFontMenuItem_Click(object sender, RoutedEventArgs e)
{
// Instantiate the dialog box
FontDialogBox dlg = new FontDialogBox();
// Configure the dialog box
dlg.Owner = this;
dlg.FontFamily = this.documentTextBox.FontFamily;
dlg.FontSize = this.documentTextBox.FontSize;
dlg.FontWeight = this.documentTextBox.FontWeight;
dlg.FontStyle = this.documentTextBox.FontStyle;
// Open the dialog box modally
dlg.ShowDialog();
// Process data entered by user if dialog box is accepted
if (dlg.DialogResult == true)
{
// Update fonts
this.documentTextBox.FontFamily = dlg.FontFamily;
this.documentTextBox.FontSize = dlg.FontSize;
this.documentTextBox.FontWeight = dlg.FontWeight;
this.documentTextBox.FontStyle = dlg.FontStyle;
}
}
// Detect when document has been altered
void documentTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
this.needsToBeSaved = true;
}
void OpenDocument()
{
// Instantiate the dialog box
OpenFileDialog dlg = new OpenFileDialog();
// Configure open file dialog box
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".wpf"; // Default file extension
dlg.Filter = "Word Processor Files (.wpf)|*.wpf"; // Filter files by extension
// Open the dialog box modally
Nullable<bool> result = dlg.ShowDialog();
// Process open file dialog box results
if (result == true)
{
// Open document
string filename = dlg.FileName;
}
}
void SaveDocument()
{
// Configure save file dialog
SaveFileDialog dlg = new SaveFileDialog();
dlg.FileName = "Document"; // Default file name
dlg.DefaultExt = ".wpf"; // Default file extension
dlg.Filter = "Word Processor Files (.wpf)|*.wpf"; // Filter files by extension
// Show save file dialog
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog results
if (result == true)
{
// Save document
string filename = dlg.FileName;
}
}
void PrintDocument()
{
// Configure printer dialog
PrintDialog dlg = new PrintDialog();
dlg.PageRangeSelection = PageRangeSelection.AllPages;
dlg.UserPageRangeEnabled = true;
// Show save file dialog
Nullable<bool> result = dlg.ShowDialog();
// Process save file dialog results
if (result == true)
{
// Print document
}
}
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 при нажатии кнопки Закрыть.
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);
}
public FindDialogBox(TextBox textBoxToSearch)
{
InitializeComponent();
this.textBoxToSearch = textBoxToSearch;
// If text box that's being searched is changed, reset search
this.textBoxToSearch.TextChanged += textBoxToSearch_TextChanged;
}
// Text to search
TextBox textBoxToSearch;
// Find results
MatchCollection matches;
int matchIndex = 0;
// Search results
int index = 0;
int length = 0;
public int Index
{
get { return this.index; }
set { this.index = value; }
}
public int Length
{
get { return this.length; }
set { this.length = value; }
}
void findNextButton_Click(object sender, RoutedEventArgs e)
{
// Find matches
if (this.matches == null)
{
string pattern = this.findWhatTextBox.Text;
// Match whole word?
if ((bool)this.matchWholeWordCheckBox.IsChecked) pattern = @"(?<=\W{0,1})" + pattern + @"(?=\W)";
// Case sensitive
if (!(bool)this.caseSensitiveCheckBox.IsChecked) pattern = "(?i)" + pattern;
// Find matches
this.matches = Regex.Matches(this.textBoxToSearch.Text, pattern);
this.matchIndex = 0;
// Word not found?
if (this.matches.Count == 0)
{
MessageBox.Show("'" + this.findWhatTextBox.Text + "' not found.", "Find");
this.matches = null;
return;
}
}
// Start at beginning of matches if the last find selected the last match
if (this.matchIndex == this.matches.Count)
{
MessageBoxResult result = MessageBox.Show("Nmore matches found. Start at beginning?", "Find", MessageBoxButton.YesNo);
if (result == MessageBoxResult.No) return;
// Reset
this.matchIndex = 0;
}
// Return match details to client so it can select the text
Match match = this.matches[this.matchIndex];
if (TextFound != null)
{
// Text found
this.index = match.Index;
this.length = match.Length;
OnTextFound();
}
this.matchIndex++;
}
void textBoxToSearch_TextChanged(object sender, TextChangedEventArgs e)
{
ResetFind();
}
void findWhatTextBox_TextChanged(object sender, TextChangedEventArgs e)
{
ResetFind();
}
void criteria_Click(object sender, RoutedEventArgs e)
{
ResetFind();
}
void ResetFind()
{
this.findNextButton.IsEnabled = true;
this.matches = null;
}
void closeButton_Click(object sender, RoutedEventArgs e)
{
// Close dialog box
this.Close();
}
}
}
См. также
- Общие сведения о контекстном меню
- Примеры диалоговых окон
ВикиЧтение
Язык программирования С# 2005 и платформа .NET 2.0. [3-е издание]
Троелсен Эндрю
Свойство DialogResult
В качестве заключительного задания при создании пользовательского интерфейса выберите кнопку OK в окне проектирования формы и найдите свойство DialogResult. Назначьте DialogResult.OK кнопке OK и DialogResult.Cancel – кнопке Отмена. Формально говоря, вы можете назначить свойству DialogResult любое значение из перечня DialogResult.
public enum System.Windows.Forms.DialogResult {
Abort, Cancel, Ignore, No,
None, OK, Retry, Yes
}
Но что же означает присваивание значения свойству DialogResult элемента Button? Это свойство может быть назначено для любого типа Button (как и для самой формы), и оно позволяет родительской форме определить, какую из кнопок выбрал конечный пользователь. Для примера измените обработчик меню Сервис? Настройка в рамках типа MainForm так, как предлагается ниже,
private void configureToolStripMenuIteimClick(object sender, EventArgs e) {
// Создание экземпляра UserMessageDialog.
UserMessageDialog dlg = new UserMessageDialog();
// Размещение текущего сообщения в TextBox.
dlg.Message = userMessage;
// Если пользователь щелкнул на кнопке OK, отобразить сообщение.
if (DialogResult.OK == dlg.ShowDialog()) {
userMessage = dlg.Message;
Invalidate();
}
// Лучше, чтобы очистку внутренних элементов выполняло само
// диалоговое окно, не дожидаясь сборщика мусора.
dlg.Dispose();
}
Здесь UserMessageDialog отображается с помощью вызова ShowDialog(). Этот метод запустит форму в виде модального диалогового окна, а это, как вы знаете, означает, что пользователь не сможет перейти к главной форме, пока диалоговое окно не будет закрыто. После закрытия диалогового окна пользователем (с помощью щелчка на кнопке OK или на кнопке Отмена), форма станет невидимой, но все еще будет оставаться в памяти. Поэтому вы можете запросить у экземпляра UserMessageDialog (с именем dlg) информацию о новом значении Message в том случае, когда пользователь щелкнул на кнопке OK. В этом случае вы отображаете новое сообщение, иначе не делаете ничего.
Замечание. Чтобы отобразить немодальное диалоговое окно (которое позволяет переходить от родительской формы к диалоговой и обратно), следует вызвать Show(), а не ShowDialog().
Читайте также
Свойство content
Свойство content
Это свойство используется вместе с псевдоэлементами: before и: after для генерации содержимого в документе. В примерах выше мы уже использовали это свойство. Теперь разберем его подробно.Свойство content может принимать одно из нескольких значений: строку текста,
Свойство Arguments
Свойство Arguments
В следующем примере (листинг 1.1) с помощью цикла for на экран выводятся все параметры командной строки, с которыми был запущен сценарий.Листинг 1.1. Вывод на экран всех параметров сценария/*******************************************************************//* Имя:
Свойство Arguments
Свойство Arguments
В листинге 1.20 приведен пример сценария, создающего ярлык на этот самый сценарий с двумя параметрами командной строки.Листинг 1.20. Создание ярлыка на выполняемый сценарий с аргументами командной строки/*****************************************************************//* Имя:
Свойство HotKey
Свойство HotKey
Для того чтобы назначить ярлыку «горячую» клавишу, необходимо в свойство HotKey записать строку, содержащую названия нужных клавиш, разделенные символом «+».
Замечание
«Горячие» клавиши могут быть назначены только ярлыкам, которые расположены на рабочем столе
Свойство IconLocation
Свойство IconLocation
Для того чтобы задать значок для ярлыка, необходимо в свойство IconLocation записать строку следующего формата: «путь, индекс». Здесь параметр путь определяет расположение файла, содержащего нужный значок, а параметр индекс — номер этого значка в файле (номера
Свойство HelpLink
Свойство HelpLink
Свойства Target Site и StackTrace позволяют получить информацию о данном исключении программисту, но конечному пользователю эта информация мало что дает. Вы уже видели, что для получения информации, понятной обычному пользователю, можно использовать свойство
Свойство Data
Свойство Data
Свойство Data объекта System.Exception является новым в .NET 2.0 и позволяет добавить в объект исключения дополнительную информацию для пользователя (например, штамп времени или что-то другое). Свойство Data возвращает объект, реализующий интерфейс с именем IDictionary,
Свойство Name
Свойство Name
Приведенный выше программный код достаточно понятен, но обратите внимание на то, что класс Thread предлагает свойство с именем Name (имя). Если вы не установите для него значения, свойство Name будет возвращать пустую строку. Но, назначив данному объекту Thread в
Свойство Priority
Свойство Priority
Далее заметим, что тип Thread определяет свойство с именем Priority. По умолчанию все потоки получают приоритет Normal (средний). Но вы можете изменить это значение в любой момент времени существования потока, используя свойство Priority и связанный с ним перечень
Свойство Anchor
Свойство Anchor
В Windows Forms свойство Anchor используется для определения относительной фиксированной позиции, в которой всегда должен пребывать данный элемент управления. Каждый производный от Control тип имеет свойство Anchor, которое может принимать любое из значений перечня
Свойство Dock
Свойство Dock
Другой особенностью программирования Windows Forms является возможность задать cтыковочное поведение элементов управления. С помощью свойства Dock элемента управления можно указать, какой стороны (или каких сторон) формы должен касаться данный элемент. Значение,
Свойство IsPostBack
Свойство IsPostBack
Еще одним очень важным членом HttpRequest является свойство IsPostBack. Напомним, что «postback» обозначает вторичное обращение к конкретной Web-странице в ходе одного сеанса связи с сервером. С учетом этого должно быть понятно, что свойство IsPostBack возвращает true (истина),
Свойство AutoPostBack
Свойство AutoPostBack
Следует также подчеркнуть то, что многие Web-элементы управления ASP.NET поддерживают свойство AutoPostBack (это очень важно для CheckBox, RadioButton и TextBox, а также для элементов управления, получаемых из абстрактного типа ListControl). По умолчанию это свойство получает значение
Свойство Name
Свойство Name
Последним из рассматриваемых здесь свойств типа WebServiceAttribute является свойство Name, которое используется для указания имени Web-сервиса XML, водимого внешним пользователем. По умолчанию внешнее имя Web-сервиса идентично имени соответствующего типа класса (которым,
Свойство FormBorderStyle
Свойство FormBorderStyle
Свойство FormBorderStyle определяет стиль формы. По умолчанию используется стиль FormBorderStyle.FixedSingle. При этом форма заполняет все рабочее место экрана, и пользователь не может изменять размеры формы или перемещать ее по экрану. При установке значения FormBorderStyle.None
Свойство ControlBox
Свойство ControlBox
Свойство ControlBox отвечает за отображение контейнера для элемента управления. Если свойство ControlBox имеет значение True, то контейнер будет отображаться. В противном случае он на экран не выводится. Для устройств Pocket PC подобный контейнер может содержать только