复合视图模式:将子视图中的错误消息传递到主视图

时间:2014-06-17 08:13:35

标签: design-patterns mvvm

我在如何将子视图中的错误消息传递到主视图方面遇到了一些问题。

我的应用程序使用UI的复合视图模式。这意味着每个页面都有子页面。每个页面都使用MVVM模式

下面是一个窗口的示例结构:

AddRecipePage
    BasisInformationPage
    AddIngredientPage
        QuantityPage
    ListIngredientsPage

    Save button

此AddRecipe使用中介模式:当您在AddIngredientPage中添加成分时,将发送Messages.IngredientsChanged消息。 ListIngredientsPage收听并自行更新。

每个子页面都接收介体类作为参数。每个子页面都会创建自己的viewmodel。

示例:

public AddIngredientsPage(Recipe recipe,Mediator mediator){
    this._recipe = recipe;
    this._mediator= mediator;
    this.DataContext = new AddIngredientsViewModel(recipe, mediator);
}

viewModel不知道视图,每个页面只知道自己的视图模型。

现在我的问题是:当用户在quantityPage中输入无效信息时,我希望当用户点击AddRecipePage中的保存按钮时弹出一个错误对话框。对话框应该提供有意义的错误消息。

那么如何在页面之间传达错误信息?

我看到了两种可能的解决方案:

  1. 在Quantity页面的viewModel中添加一个getErrorMessage()方法,然后将此消息放入链中的每个Page和viewModel中,直到我到达AddRecipeViewModel(然后还需要知道AddRecipePage才能到达它)。这会给我带来非常混乱的代码,所以我不喜欢这个。
  2. 使用介体:介体不是真正用于错误处理的。然后,当某些文本框失去焦点而不是单击保存按钮时,它将需要发送消息。它可以接收diffeenrt控件的多个错误消息,然后需要将它们存储在AddRecipeViewModel中以显示所有这些消息。但是当用户输入无效输入并且在同一消息中输入正确的输入后,应该删除AddRecipeViewModel中存储的错误消息。所以这也是一个糟糕的解决方案。
  3. 任何人都有更好的主意吗?

    谢谢你的帮助。

1 个答案:

答案 0 :(得分:1)

您正在寻找的是Event Aggregator模式。请记住,错误报告和处理几乎是每个软件程序的域无关功能,因此,不应该是视图模型的一部分,而应作为单独的组件处理。

您提出的两个解决方案都违反了Single Responsibility Principle,并且我会在这个前提下避免使用它们(它们会为具有已明确定义的职责的组件添加错误处理的额外责任)。

返回事件聚合器。你需要的是一个组件(我们称之为错误演示者),它将订阅事件聚合器的错误事件(由视图模型或视图引发,具体取决于错误上下文)。然后,此类组件将实例化相应的错误视图并将其显示给用户:

// Ingridients V/VM
if (!IsValid(ingridient))
    eventAggregator.Publish(new MissingIngridientsError(ingridient.Name));

// Error presenter
eventAggreagtor.Subscribe<Error>(this.DisplayErrorPopup);

// DisplayErrorPopup
var errorViewModel = new ErrorViewModel(error);
var errorPopupView = new ErrorPopupView(errorViewModel);
errorPopupView.Show();

请注意,要使此类设置生效,EventAggregator必须是应用程序范围的组件,最有可能是单个实例。