2010-11-14 155 views
12

我开始我的第一次进入Prism v4/MVVM世界与MEF & WPF。我成功地构建了一个shell,使用MEF,我能够发现和初始化模块。然而,我不确定导航到这些模块公开的视图的正确方式。棱镜/ MVVM(MEF/WPF):暴露导航[菜单例如]从模块

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

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

我环顾四周,在使用“服务”提供导航的某些网站上提到,因此在模块初始化期间,导航选项被添加到服务中,而服务又被shell使用来显示此导航以任何格式(ToolBarTreeViewRibbonMenuItem等) - 但我找不到任何实际做到这一点的例子。我最终希望能够从菜单和/或其他导航控件(可能是Ribbon)中选择视图,然后在TabControl中按需打开这些视图。我已经尽可能在模块初始化时创建了TabControl中的视图,现在我需要下一步。

我需要知道的是:以这种方式公开导航选项的正确方法是什么,而不是坚持支持shell的特定控件,并且如果服务是要走的路如何将这些结合到Prism/MVVM模式中。

在此先感谢您提供的任何见解。

回答

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属性来填充你的菜单。

+0

我有点像这样,因为它是一个完全通用的选项,让shell决定它将如何显示项目。也就是说,我对这个问题有了进一步的思考,并且实际上已经走过了另一条路线,我将其作为一个单独的答案来记录。谢谢。 – 2010-11-21 13:05:09

+0

不要忘记你可以制作一个MenuItemViewModel适合MenuItems(可检查或有子项目)。你将不得不做出更具体的界面。但这是一个例子。玩的开心。 – SandRock 2010-11-21 13:26:33

1

考虑到这一点,我得出以下结论,我觉得影响我需要处理这个问题的方式......

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

因此,模块需要设计为与外壳进行交互以将内容放入命名区域,因此我没有理由说明模块不应该公开外壳支持的任何类型的导航。因此,我的模块(当前)公开了一个带有必要的图标,按钮和命令等的“RibbonView”(RibbonTab)以显示模块的功能。每个“RibbonView”都用shell的“RibbonRegion”注册,并提供订购提示,然后在shell中进行渲染。

如果将来我会选择更新我的shell以使用最新的+最大的导航控件(不管可能在x年的时间),那么我只需要更新每个模块以公开必要的项目与新的导航集成,并且因为我正在加载到一个新的外壳,我可以相应地更新我的视图注册。

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

我很想听听有没有人对此有任何意见。

0

我遇到过同样的情况,我认为解决方案在于区分接口和实现。例如,您可以在执行给定功能的模块中设计视图。就是这样。只要您在特定的环境中使用或使用此功能,您就已经跨越了实施。现在,理想情况下,该视图并不知道它是如何实现的,当然也不知道壳牌中的命名区域。所以,在一个模块内对区域进行坐席是一个不错的选择。

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

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

这可能会给你解决这个问题的一些想法。

希望它有帮助。

+0

我完全同意,通过了解shell的区域,我的模块被绑定到特定的实现,但直到现在我还在为如何绕过这个想法而挣扎。虽然您的文章并未直接解决我的情况(您只有一个区域,并且您完全知道要加载的视图以便将它们放入您的配置中),但它为我提供了一些关于如何绕过问题。谢谢。 – 2010-12-03 09:05:36

0

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

如果您将IMenuItem更改为INavigationItem,您就得到了您想要的。

在那篇文章中,当特定导航项被通知它已经“运行”时,它通常实例化一个文档或“pad”的ViewModel,并将其传递给ILayoutManager服务。它有一个可插拔的架构,所以你可以换出一个不同的布局引擎的LayoutManager服务(默认的是AvalonDock的包装)。