Prism / MVVM(MEF / WPF):从模块公开导航[例如菜单]

时间:2010-11-14 17:40:20

标签: wpf navigation prism mef

我开始首次涉足Prism v4 / MVVM的世界,MEF& WPF。我成功构建了一个shell,使用MEF,我能够发现并初始化模块。但是,我不确定如何为这些模块公开的视图提供导航的正确方法。

例如,假设其中一个模块公开了三个视图,我想在菜单控件上显示这些视图的导航。到目前为止,我已成功地基于MenuItem公开了一个视图,并且此MenuItem包含子MenuItem控件,因此提供了可以使用的命令层次结构。大。

事情是,这感觉不对。我现在在我的模块中说明导航(因此shell)必须支持使用菜单。如果我想更改为使用ToolBar甚至Ribbon,该怎么办?然后我必须更改所有模块以显示shell的相应控件类型。

我环顾四周并且在一些网站上提到使用“服务”来提供导航,在模块初始化期间,导航选项被添加到服务中,而服务又被shell用来显示这个以他们想要的任何格式导航(ToolBarTreeViewRibbonMenuItem等等 - 但我找不到任何实际执行此操作的示例。

为了全面了解这一点,我最终希望能够从菜单和/或其他导航控件(可能是Ribbon)中选择视图,然后在TabControl中按需打开这些视图。我已经知道能够在模块初始化时在TabControl创建视图,现在我需要下一步。

我需要知道的是:以这样的方式公开导航选项的正确方法是什么,而不是坚持支持shell的特定控件,如果服务是方式,那么如何将这一点放在Prism / MVVM模式中。

提前感谢您提供的任何见解。

4 个答案:

答案 0 :(得分:7)

我想你有一个包含通用接口的主模块。 您可以创建一个简单的界面,如

public interface IMenuService {
    void AddItem(string name, Action action);
    IEnumerable<MenuItemViewModel> GetItems { get; }
}

创建1个实现和单个实例。

public class MenuService : IMenuService {

    private readonly IList<MenuItemViewModel> items = new List<MenuItemViewModel>();

    void AddItem(string name, Action action) {
        items.Add(new MenuItemViewModel {
            Name = name,
            Action = action
        });
    }

    IEnumerable<MenuItemViewModel> GetItems {
        get { return list.AsEnumerable(); }
    }
}

在您的模块中,使用MEF解析此实例并致电AddItem()注册您的观看次数。 Action属性是一个简单的委托,用于激活视图或执行任何其他操作。

然后在您的shell或任何视图中,您只需调用GetItems属性来填充菜单。

答案 1 :(得分:1)

在考虑了这个之后,我得出以下结论:我感觉影响了我需要处理的方式......

模块需要部分了解shell布局 - 也就是说,shell暴露了许多区域,模块需要知道这些区域(按名称以及预期显示的内容)为了在请求功能时正确填充它们(通过在区域内注册视图或作为对用户操作的反应)。

因此,模块需要设计为与shell交互以将内容放入命名区域,因此,我认为模块不应暴露shell支持的任何类型的导航。

因此,我的模块(当前)使用必要的图标,按钮和命令等公开“RibbonView”(RibbonTab)以显示模块的功能。每个“RibbonView”都会在shell的“RibbonRegion”中注册,并提供有关排序的提示,然后在shell中进行渲染。

如果将来我选择更新我的shell以使用最新的+最好的导航控件(无论是 x 年的时间),那么我只需要更新每个模块以进行曝光与新导航集成的必要项目,因为我正在加载到新的shell中,然后我可以相应地更新我的视图注册。

我只是希望我没有违反复合应用程序的任何原则,但是我说我从来没有找到一种实际上可以在没有“解释”的情况下实现的模式。

我很想知道是否有人对此有任何意见。

答案 2 :(得分:0)

我遇到了同样的情况,我认为解决方案在于区分接口和实现。例如,您可以在执行给定功能的模块中设计视图。就是这样。只要您在特定的上下文中使用或使用它,您就会越过实现。现在,理想情况下,视图不知道它是如何实现的,当然也不会知道Shell中的命名区域。因此,在模块内的区域中放置视图是禁止的。

为了解决这个问题,我选择将此职责委托给第三方组件LayoutManager。 LayoutManager位于Shell和Module之间,用于定义“什么在哪里”。它是一个特定的实现,并且真正定义了实现。 Shell和Module视图都是通用的。

查看:http://rgramann.blogspot.com/2009/08/layout-manager-for-prism-v2.html

这可能会就这个问题给你一些想法。

希望它有所帮助。

答案 3 :(得分:0)

这个article使用抽象(IMenuItem)来表示菜单选项的ViewModel。实际渲染这些导入对象的方式取决于主机应用程序。该示例使用WPF菜单,但您当然可以以任何方式呈现它,因为IMenuItem足够抽象。

如果您将IMenuItem更改为INavigationItem,那么您就拥有了所需的内容。

在那篇文章中,当特定的导航项被通知它已经“运行”时,它通常会为文档或“pad”实例化ViewModel,并将其传递给ILayoutManager服务。它具有可插入的体系结构,因此您可以将LayoutManager服务换成不同的布局引擎(默认的是AvalonDock的包装器)。