WPF MEF + Prism初始区域加载

时间:2013-10-22 19:10:17

标签: wpf mvvm prism mef

我在WPF中使用MEF和Prism在三个不同的区域编写了一个MVVM应用程序。代码跨越两个模块,在App.Config中被发现。

我的所有导航命令和结构都运行得非常好,但我感到困惑的一件事是如何设置在app启动时加载到每个区域的初始视图,因为似乎无处可以做到这一点。此外,如果我在MainViewModel构造函数的末尾添加一些东西以显式导航到屏幕集A,那么其他东西似乎会覆盖它并加载一组不同的视图来开始。

它似乎也取决于我在app.config上加载模块的顺序,这似乎是不可取的。如果我最后加载Admin模块,它会从admin模块加载一组屏幕,如果我最后加载搜索模块,它会从搜索模块加载一组视图,在这种情况下,它甚至找不到View for主要地区。

在使用MEF和配置发现时,在app启动时指定将哪些视图加载到每个区域的方法是什么?

using System;
using System.ComponentModel.Composition;
using Microsoft.Practices.Prism.Regions;

namespace CRM.GUI.WPF.Shared.Infrastructure.Behaviour
{
    [Export(typeof(AutoPopulateExportedViewsBehavior))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class AutoPopulateExportedViewsBehavior : RegionBehavior, IPartImportsSatisfiedNotification
    {
        protected override void OnAttach()
        {
            AddRegisteredViews();
        }

        public void OnImportsSatisfied()
        {
            AddRegisteredViews();
        }

        private void AddRegisteredViews()
        {
            if (Region != null)
            {
                foreach (var viewEntry in RegisteredViews)
                {
                    if (viewEntry.Metadata.RegionName == Region.Name)
                    {
                        var view = viewEntry.Value;

                        if (!Region.Views.Contains(view))
                        {
                            Region.Add(view);
                        }
                    }
                }
            }
        }

        [ImportMany(AllowRecomposition = true)]
        public Lazy<object, IViewRegionRegistration>[] RegisteredViews { get; set; }
    }
}

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
    [MetadataAttribute]
    public class ViewExportAttribute : ExportAttribute, IViewRegionRegistration
    {
        public ViewExportAttribute()
            : base(typeof(object))
        { }

        public ViewExportAttribute(string viewName)
            : base(viewName, typeof(object))
        { }

        public string RegionName { get; set; }
    }

用于

[ViewExport(RegionName = RegionNames.MainRegion)]
public partial class ReportView

2 个答案:

答案 0 :(得分:1)

根据我的理解, Prism 会默认加载并显示在每个区域上注册的第一个查看(仅限第一个如果区域设置在 ContentControl 项目上,则会显示>视图

因此,您可以停用在您不希望在startUp上显示的每个 RegionBehavior 上的不受欢迎的视图。这将使得当添加所需的 启动视图 时,它将被激活,因为没有其他活动 查看

另一种方法是在相应的模块 初始化()方法上注册每个查看,而不是使用 RegionBehaviours 。最后,在将每个查看添加到相应的区域后,您将决定停用 查看是否是是否 启动视图

<强>更新

以下实施显示了每个 RegionBehavior 停用 非启动视图的可能替代方法。为了获得更优雅的解决方案,您可以创建一个字典或一个简单的静态类,它将返回相应区域 StartUpView 名称,然后如图所示调用它下面:

private void AddRegisteredViews()
{
   ...
       var view = viewEntry.Value;

       if (!Region.Views.Contains(view))
       {
            Region.Add(view);
            if (view.GetType().Name != StartUpViewNames.getViewNameFromRegion(Region))
            {
                 Region.deactivate(view);
            }
       }
  ...
}

请注意,我找到 StartUpView 并且保持活动后,它会继续停用以下添加的视图,但您可以离开他们活跃。正如我所提到的,将显示的视图将是第一个在区域中获得 Active 的。

我希望这有帮助, 问候。

答案 1 :(得分:0)

我相信PRISM视图的理念是加载所有视图并像一堆卡片一样切换进出。在您的情况下,我可以看到您正在使用附加行为来加载每个区域的所有视图。我怀疑您正在加载所有视图并将其添加到相应的区域,但最后一个视图覆盖了其他视图(最后一个视图已添加到该区域)。在WPF中,视图层次结构中的最后一个控件在zorder中更高(因为它是最后绘制的)。以前的每个控件都可能在下面。

我建议您创建一个名为NavigationService的服务类,而不是当前的方法,它将处理按需从模块加载视图集,并卸载任何以前的视图集。您可以将其设计为状态管理器,它可以与PRISM协调不同的视图排列,即使您只想加载某些视图(比如模块视图的子集),而不是一直加载所有视图。在Bootloader中,使用NavigationService注册每个模块,并且每个模块可能包含您需要的每个视图组合的策略类,从而提供适当的行为。这样,您可以使协调逻辑保持接近其使用的视图。在您的Shell中,调用NavigationService(将注入每个视图模型以方便更改屏幕)以设置初始视图。

请记住,这只是一个完成您所需要的想法,但我会放弃WPF中的基本PRISM功能。它在复杂性方面具有限制性,非常重要性和不必要性。您仍然可以在不使用其导航设施的情况下使用PRISM的区域。