我在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
答案 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的区域。