MVVM 方式的对话框





5.00/5 (10投票s)
本文及附带的示例将展示如何使用 MVVM 的方式,通过数据绑定并在视图中不写代码后台,来处理对话框。
引言

模型-视图-视图模型 (MVVM) 模式非常出色,因为它清晰地定义了视图、视图模型和模型的职责。视图和视图模型之间不应有直接的通信,而通过数据绑定机制,这很容易实现。
然而,当需要在用户删除选择的实体之前获得用户的确认时,我遇到一个问题。负责删除行为的命令是从视图内部触发,并在视图模型内部执行的。在我看来,视图模型不应直接使用任何呈现功能(例如,显示 MessageBox)。
为了在网上找到一个合理的解决方案,我遇到了以下几种方法:
- 直接从视图模型中显示 messagebox。
- 使用一种在视图中添加额外代码的解决方案,该代码会响应来自视图模型的触发。
- 将视图绑定到一个消息属性,并在该属性更改时显示 messagebox。
- 使用现有的 MVVM 框架之一,并使用它们提供的解决方案。
解决方案 1 和 2 直接被否决,解决方案 3 接近但我觉得响应消息更改非常受限。解决方案 4 不是我的选择,因为我并不太喜欢我审查过的 MVVM 框架。
由于我无法找到符合我要求的解决方案,我提出了本文中提到的解决方案。
解决方案
使用位于 System.Windows.Interactivity 程序集中的Behavior 类,可以在视图和视图模型之间进行挂钩,而无需视图和视图模型之间的直接接触。
通过扩展这个Behavior类并添加一个功能,该功能可以根据提供的标识符集中注册 behavior 实例,这将确保视图和视图模型都可以在没有任何直接引用的情况下使用它。
这产生了以下设计:
Using the Code
InteractionBehaviorCollection
为了能够集中注册 behavior,使用了单例模式的 InteractionBehaviorCollection。根据 behavior 的标识符,它将存储 behavior 的实例,以便在需要时检索。
InteractionBehaviorBase
为了扩展Behavior类,创建了一个派生类,称为InteractionBehaviorBase。当 interaction behavior 被附加(在视图中使用)时,它将自行注册到 InteractionBehaviorCollection。当 interaction behavior 被分离时,它也将自行注销。
MessageBoxInteractionBehavior
此类包含显示常规MessageBox所需的功能。当需要自定义对话框时,可以创建另一个特定的InteractionBehavior,它将负责在视图模型需要时显示自定义对话框。
该类提供了 3 个属性,使我们能够自定义消息框。这包括标题、消息以及消息框中可能显示的按钮。
有一个方法,即 Execute 方法,该方法将显示消息框,并将结果传递给自定义代码进行处理。此处理将在视图模型中完成,以便逻辑可以响应客户端操作。
public override void Execute(
Action<Object> interactionFinished,
params object[] args)
{
if ((interactionFinished != null) &&
!string.IsNullOrEmpty(Caption) &&
!string.IsNullOrEmpty(Message))
{
string caption = string.Format(Caption, args);
string message = string.Format(Message, args);
interactionFinished(MessageBox.Show(message, caption, Buttons,
MessageBoxImage.Information));
}
}
视图, MainWindow.xaml
在视图的 XAML 中,定义了 behavior,这也包括了属性。可以包含格式字符,以便在 behavior 被视图模型触发时传递自定义信息。标识符是必需的,以便视图模型可以识别此特定 behavior。
<i:Interaction.Behaviors>
<local:MessageBoxInteractionBehavior
Caption="This contains the caption"
Message="This contains the message, parameters can also be added (For example the current date/time: {0})"
Buttons="YesNo"
Identifier="ThisIdentifiesThisSpecificCombination"/>
</i:Interaction.Behaviors>
ViewModelBase
这是所附示例中使用的特定视图模型的基类。它包含 ExecuteInteraction 方法,该方法允许使用相应的标识符触发 interaction behavior。
// Find the matching interaction behavior.
IInteractionBehavior interactionBehavior =
InteractionBehaviorCollection.Instance.Get(identifier);
if (interactionBehavior != null)
{
try
{
interactionBehavior.Execute(interactionFinished, args);
result = true;
}
catch (Exception)
{
}
}
TestViewModel
此测试应用程序使用的视图模型。它提供了一个触发 interaction behavior 的命令,通过 TestInteractionBehaviorCommand 属性使用。从视图模型内部实际触发消息框的操作位于 TestInteractionBehavior 方法中。
private void TestInteractionBehavior()
{
ExecuteInteraction("ThisIdentifiesThisSpecificCombination", (result) =>
{
MessageBoxResult messageBoxResult = (MessageBoxResult)result;
if (messageBoxResult == System.Windows.MessageBoxResult.Yes)
{
// We know that the user selected the option Yes.
}
}, DateTime.Now);
}
调用 ExecuteInteraction 将触发与标识符 "ThisIdentifiesThisSpecificCombination" 匹配的 interaction behavior。消息框的结果会被接收,并可用于处理所需的客户端操作。可以传递参数以便自定义消息,例如,显示正在删除的实体的名称。在此示例中,我坚持使用当前日期/时间。
调用 ExecuteInteraction 时将显示以下消息框:
关注点
此示例使用默认消息框与用户交互。根据本示例中的信息,将其替换为更适合您需求的自定义视图应该不是问题。
历史
- 2014 年 1 月 9 日:初版