Windows Presentation Foundation (WPF)提供了设计自己的对话框的方法。 对话框是窗口,但具有特定的意向和用户体验。 本文讨论对话框的工作原理以及可以创建和使用哪种类型的对话框。 对话框用于:
- 向用户显示特定信息。
- 从用户收集信息。
- 显示和收集信息。
- 显示作系统提示,例如打印窗口。
- 选择文件或文件夹。
这些类型的窗口称为 对话框。 可以通过两种方式显示对话框:模式和无模式。
向用户显示 模式 对话框是一种技术,应用程序会中断其正在执行的作,直到用户关闭对话框。 这通常以提示或警报的形式出现。 在关闭对话框之前,应用程序中的其他窗口无法与之交互。 关闭 模式 对话框后,应用程序将继续运行。 最常见的对话框用于显示打开的文件或保存文件提示、显示打印机对话框或向用户发送某些状态的消息。
无模式对话框不会阻止用户在打开时激活其他窗口。 例如,如果用户想要查找文档中特定单词的出现次数,主窗口通常会打开一个对话框,询问用户要查找的单词。 由于应用程序不想阻止用户编辑文档,因此无需模式对话框。 无模式对话框至少提供一个“关闭”按钮,用于关闭该对话框。 可以提供其他按钮来运行特定函数,例如 “查找下一个” 按钮,用于在字词搜索中查找下一个单词。
使用 WPF,可以创建多种类型的对话框,例如消息框、常见对话框和自定义对话框。 本文讨论了每个示例, 对话框示例 提供了匹配的示例。
消息框
消息框是一个对话框,可用于显示文本信息并允许用户使用按钮做出决策。 下图显示了一个消息框,其中询问了一个问题,并为用户提供了三个按钮来回答问题。
若要创建消息框,请使用该 MessageBox 类。 MessageBox 允许配置消息框文本、标题、图标和按钮。
有关详细信息,请参阅 “如何打开消息”框。
常见对话框
Windows 实现所有应用程序通用的各种可重用对话框,包括用于选择文件和打印的对话框。
由于这些对话框由作系统提供,因此它们在所有在作系统上运行的应用程序之间共享。 这些对话框提供一致的用户体验,称为 常见对话框。 当用户在一个应用程序中使用通用对话框时,无需了解如何在其他应用程序中使用该对话框。
WPF 封装打开的文件、保存文件、打开文件夹并打印常用对话框,并将其公开为托管类供你使用。
若要了解有关常见对话框的详细信息,请参阅以下文章:
自定义对话框
虽然常见对话框很有用,应尽可能使用,但它们不支持领域特定的对话框的要求。 在这些情况下,需要创建自己的对话框。 如我们所看到的,对话框是具有特殊行为的窗口。 Window 实现这些行为,然后使用窗口创建自定义模态和非模态对话框。
创建自己的对话框时,需要考虑许多设计注意事项。 尽管应用程序窗口和对话框都包含相似之处,例如共享同一基类,但对话框用于特定目的。 通常需要一个对话框,当你需要提示用户输入某种信息或响应时。 通常,当显示对话框(模式)时,应用程序将暂停,从而限制对应用程序的其余部分的访问。 关闭对话框后,应用程序将继续。 不过,仅将交互限制在对话框上并不是一项要求。
当 WPF 窗口关闭时,它无法重新打开。 自定义对话框是 WPF 窗口,应用相同的规则。 若要了解如何关闭窗口,请参阅 如何关闭窗口或对话框。
实现对话框
设计对话框时,请按照以下建议创建良好的用户体验:
❌ 不要将对话框窗口杂乱无章。 对话框体验是让用户输入某些数据或做出选择。
✔️ 请提供 “确定 ”按钮以关闭窗口。
✔️ 请设置 “确定 ”按钮 IsDefault 的属性 true
,以允许用户按 Enter 键接受并关闭窗口。
✔️ 请考虑添加 “取消” 按钮,以便用户可以关闭窗口并指示他们不想继续。
✔️ 请设置 “取消” 按钮 IsCancel 的属性 true
以允许用户按 ESC 键关闭窗口。
✔️ DO 设置窗口标题,以准确描述对话框的内容或用户应如何处理对话框。
✔️ 请为窗口设置最小宽度和高度值,防止用户调整窗口大小过小。
✔️ 如果 ShowInTaskbar 设置为 false
,请考虑禁用调整窗口大小的功能。 可以通过设置ResizeMode为NoResize来禁用调整大小。
以下代码演示了此配置。
<Window x:Class="Dialogs.Margins"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Change Margins"
Closing="Window_Closing"
MinHeight="200"
MinWidth="300"
SizeToContent="WidthAndHeight"
ResizeMode="NoResize"
ShowInTaskbar="False"
WindowStartupLocation="CenterOwner"
FocusManager.FocusedElement="{Binding ElementName=leftMarginTextBox}">
<Grid Margin="10">
<Grid.Resources>
<!-- Default settings for controls -->
<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>
<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,Top,Right,Bottom margins-->
<Label Grid.Column="0" Grid.Row="0">Left Margin:</Label>
<TextBox Name="leftMarginTextBox" Grid.Column="1" Grid.Row="0" />
<Label Grid.Column="0" Grid.Row="1">Top Margin:</Label>
<TextBox Name="topMarginTextBox" Grid.Column="1" Grid.Row="1"/>
<Label Grid.Column="0" Grid.Row="2">Right Margin:</Label>
<TextBox Name="rightMarginTextBox" Grid.Column="1" Grid.Row="2" />
<Label Grid.Column="0" Grid.Row="3">Bottom Margin:</Label>
<TextBox Name="bottomMarginTextBox" Grid.Column="1" Grid.Row="3" />
<!-- Accept or Cancel -->
<StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="4" Orientation="Horizontal" HorizontalAlignment="Right">
<Button Name="okButton" Click="okButton_Click" IsDefault="True">OK</Button>
<Button Name="cancelButton" IsCancel="True">Cancel</Button>
</StackPanel>
</Grid >
</Window>
上面的 XAML 创建一个类似于下图的窗口:
打开对话框的 UI 元素
对话框的用户体验也会扩展到菜单栏或打开它的窗口按钮。 当菜单项或按钮运行需要用户通过对话框交互才能继续的函数时,控件应在其标题文本的末尾使用省略号:
<MenuItem Header="_Margins..." Click="formatMarginsMenuItem_Click" />
<!-- or -->
<Button Content="_Margins..." Click="formatMarginsButton_Click" />
当菜单项或按钮运行显示 不需要 用户交互的对话框(例如 “关于 ”对话框)的函数时,不需要省略号。
菜单项
菜单项是一种常见的方法,通过将应用程序操作分组到相关主题中来为用户提供服务。 你可能已在许多不同的应用程序中看到 “文件” 菜单。 在典型的应用程序中, “文件” 菜单项提供了保存文件、加载文件以及打印文件的方法。 如果动作将显示一个模式窗口,标题通常包括省略号,如下图所示:
其中两个菜单项有省略号: ...
。 这有助于用户确定当他们选择这些菜单项时,会显示模式窗口,暂停应用程序,直到用户关闭它。
这种设计技术是一种简单的方法,可让你向用户传达他们期望的内容。
按钮
可以遵循 “菜单项” 部分中所述的相同原则。 使用按钮文本上的省略号指示当用户按下按钮时,将显示模式对话框。 在下图中,有两个按钮,很容易理解哪个按钮显示对话框:
返回结果
打开另一个窗口(尤其是模式对话框)是返回状态和调用代码信息的好方法。
模态对话框
通过调用 ShowDialog()显示对话框时,打开对话框的代码将等待方法 ShowDialog
返回。 方法返回时,调用它的代码需要决定是否继续处理还是停止处理。 用户通常通过按对话框中的 “确定 ”或 “取消” 按钮来指示这一点。
按下“确定”按钮时,ShowDialog
应设计为返回true
;按下“取消”按钮时,应返回false
。 这可以通过在按下按钮时设置 DialogResult 属性来实现。
private void okButton_Click(object sender, RoutedEventArgs e) =>
DialogResult = true;
private void cancelButton_Click(object sender, RoutedEventArgs e) =>
DialogResult = false;
Private Sub okButton_Click(sender As Object, e As RoutedEventArgs)
DialogResult = True
End Sub
Private Sub cancelButton_Click(sender As Object, e As RoutedEventArgs)
DialogResult = False
End Sub
仅当对话框通过ShowDialog()显示时,才能设置DialogResult属性。
DialogResult
设置属性后,对话框将关闭。
如果按钮的 IsCancel 属性设置为 true
,并且窗口使用 ShowDialog() 打开,则 ESC 键将关闭窗口,并设置 DialogResult
为 false
。
有关关闭对话框的详细信息,请参阅 如何关闭窗口或对话框。
处理响应
返回 ShowDialog() 一个布尔值,指示用户是接受还是取消了对话框。 如果要向用户发出警报,但不需要他们做出决策或提供数据,则可以忽略响应。 还可以通过检查 DialogResult 属性来检查响应。 以下代码演示如何处理响应:
var dialog = new Margins();
// Display the dialog box and read the response
bool? result = dialog.ShowDialog();
if (result == true)
{
// User accepted the dialog box
MessageBox.Show("Your request will be processed.");
}
else
{
// User cancelled the dialog box
MessageBox.Show("Sorry it didn't work out, we'll try again later.");
}
Dim marginsWindow As New Margins
Dim result As Boolean? = marginsWindow.ShowDialog()
If result = True Then
' User accepted the dialog box
MessageBox.Show("Your request will be processed.")
Else
' User cancelled the dialog box
MessageBox.Show("Sorry it didn't work out, we'll try again later.")
End If
marginsWindow.Show()
非模态对话框
若要无模式显示对话框,请调用 Show()。 对话框至少应提供 “关闭 ”按钮。 可以提供其他按钮和交互式元素来运行特定函数,例如 “查找下 一个”按钮,用于在字词搜索中查找下一个单词。
由于无模式对话框不会阻止调用代码继续执行,因此必须提供另一种返回结果的方法。 可以执行以下操作之一:
- 在窗口上公开数据对象属性。
- 在调用代码中处理Window.Closed事件。
- 在用户选择对象或按特定按钮时引发的窗口中创建事件。
以下示例使用 Window.Closed 事件在对话框关闭时向用户显示消息框。 显示的消息引用关闭对话框的属性。 有关关闭对话框的详细信息,请参阅 如何关闭窗口或对话框。
var marginsWindow = new Margins();
marginsWindow.Closed += (sender, eventArgs) =>
{
MessageBox.Show($"You closed the margins window! It had the title of {marginsWindow.Title}");
};
marginsWindow.Show();
Dim marginsWindow As New Margins
AddHandler marginsWindow.Closed, Sub(sender As Object, e As EventArgs)
MessageBox.Show($"You closed the margins window! It had the title of {marginsWindow.Title}")
End Sub
marginsWindow.Show()