【问题标题】:WPF MEF + Prism initial Region loadingWPF MEF + Prism 初始区域加载
【发布时间】:2013-10-31 19:41:12
【问题描述】:

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

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

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

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

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

【问题讨论】:

  • 嗨!真的很难说。您是否有导入视图的区域行为?可以发一下吗?
  • 已更新以包含代码
  • 看起来不错,如果在 OnAttach() 方法中设置断点:是否命中,RegisteredViews 包含什么?你也可以发布外壳吗?

标签: wpf mvvm prism mef


【解决方案1】:

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

因此,您可以停用您不想在启动时显示的每个 RegionBehavior 上的不想要的 Views。这将使得当添加所需的 StartUp View 时,它将被 激活,因为没有其他 活动 查看

另一种选择是在相应的 Module initialize() 方法上注册每个 View,而不是使用 RegionBehaviours强>。所以最后,在将每个 View 添加到相应的 Region 之后,您将决定停用 View,无论它是StartUp View 与否。

更新:

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

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 并保持 活动 后,我会继续停用以下添加的 视图,但您可以离开他们活跃。正如我所提到的,将显示的 View 将是第一个在 RegionActive 的。

我希望这会有所帮助, 问候。

【讨论】:

  • 感谢您的回复。您能否澄清一下,我将如何停用对区域行为的看法?我通过删除我为自动发现不需要的视图而添加的自定义属性解决了这个问题,因此我只得到一个在启动时显示的带有 [ViewExport] 属性的属性,但是当我导航时,它仍然会找到其他视图。如果我没有为它们提供 [ViewExport] 属性并将它们添加到该区域,如何找到它们?它们是否被添加到其他地方?
  • 确认一下,我在另一个视图上只有一个 [Export] 属性,没有提到我希望它添加到哪个区域,所以我看不到我指定放置哪个区域的任何地方它在,只有当我执行 regionmanager.RequestNavigate("regionname", "viewname") 时,我才能看到这个视图与区域相关联的唯一位置,但它仍然可以正常工作并正确显示,这让我感到困惑,好像我不需要 [ViewExport(RegIonName="RegionName"] 属性,我为什么还要这样做?没有那个属性,我粘贴的自动发现代码肯定不会选择这个视图?
  • [Export] 属性使 View 被注册到 MEF 容器中。当您第一次导航到目标 View 时,它还没有注册到 Region。但是,如果在 Region's Views上找不到 ViewRequestNavigate() 方法会在 MEF 容器中查找 View > 收藏。因此,在容器中注册了ViewView被添加到Region中,之后进行Navigation。
  • 您可以在Managing Dependencies Prism MSDN 章节或Prism 库源代码中找到更多相关信息,该库源代码可供下载@ 987654322@。我希望这对你有所帮助。
【解决方案2】:

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

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

请记住,这只是完成您需要的一个想法,但我会远离 WPF 中的基本 PRISM 功能。它是限制性的,恕我直言,并且在复杂性方面是不必要的。您仍然可以使用 PRISM 的区域而不使用其导航工具。

【讨论】:

  • 感谢您的回复,这是一个很好的评论,我会研究这种类型的东西来替换 Prism 行为,因为我不喜欢在每个模块中声明相同的重复导航控制器帮助代码
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多