PRISM 4 - RegisterViewWithRegion&自定义导出属性

时间:2011-06-07 20:23:04

标签: prism mef regions

我正在使用Prism 4和MEF Extensions以及MVVM模式。在模块初始化期间,我调用RegisterViewWithRegion(RegionNames.MyRegion,typeof(MyView)),当视图构造如下时,它可以正常工作:

[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class MyView : UserControl
{
    public MyView()
    {
     ....

视图已注册,一切正常。只要我将导出更改为自定义导出属性,就无法再找到视图,尽管它仍在容器中。此自定义导出属性取自Stock Trader RI:

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

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

    public string RegionName { get; set; }
    public string ViewName { get; set; }

}

,界面是

public interface IViewRegionRegistration
{
    string RegionName { get; }
    string ViewName { get; }
}

将导出属性更改为

[ViewExport(ViewName = "MyView", RegionName = RegionNames.MyRegion)]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class MyView : UserControl
{
    public MyView()
    {
    ....

调用RegisterViewWithRegion时会抛出错误:尝试获取MyView类型的实例时出现激活错误,键“”

有什么建议吗?我整天都在查看这部分代码而没有找到解决方案。

4 个答案:

答案 0 :(得分:4)

另一天,另一种方式......即使我对PRISM知之甚少,我也会尝试回答我的问题。换句话说:我还在学习。

来自Stock Trade RI的自定义导出属性由AutoPopulateExportedViewsBehavior使用。此行为通过检查区域名称的“导出属性”自动将视图添加到其区域,然后将视图添加到相应的区域。但是,使用此自定义属性的所有视图现在都具有合同名称“object”,这使得ServiveLocator无法找到它们。此自定义属性适用于具有固定区域/视图链接的方案。 使用自定义导出属性时的解决方案是获取“object”类型的所有导出以及相应的元数据:

MyView view;
var myList = container.GetExports<object, IViewRegionRegistration>();
foreach (Lazy<object, IViewRegionRegistration> lazy in myList)
{
    if (lazy.Metadata.ViewName == "MyView")
    {
        view = lazy.Value as MyView;
        region.Add(view);
        break;
    }
}

但我认为使用ViewInjection和Prism Navigation时最好只使用默认的[Export]属性,然后一切顺利。

答案 1 :(得分:4)

您是否在MEF引导程序中配置聚合目录?如果是这样,您是否添加包含ViewExportAttribute和AutoPopulateExportedViewsBehavior类的程序集?我相信这种情况发生在StockTraderRI的引导程序中:

this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(StockTraderRICommands).Assembly));

StockTraderRICommands类与ViewExportAttribute和AutoPopulateExportedViewsBehavior类位于同一个程序集中。

答案 2 :(得分:0)

自定义导出属性将typeof(object)传递给基础构造函数,后者会更改导出的合同,使其不再与导入匹配。更改它,以便调用无参数构造函数。

就激活错误而言,您需要更详细地查看异常。根本原因可能在某处,可能埋藏在InnerException下。

答案 3 :(得分:0)

我遇到了完全相同的问题,对于MEF / PRISM初学者来说这是一个很难的问题。 okieh很好地描述了这个问题,我只想发布一个替代解决方案,来自 StocktraderUI示例应用程序

如果您希望在没有任何形式的配置文件等的情况下查看发现,那么解决方案可以(/似乎可以工作),您必须注册视图。

<强> 1。修改ViewExport自定义事件

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

    public string ViewName { get { return base.ContractName; } }

    public string RegionName { get; set; }
}

添加[Export]属性,现在使用UserControl而不是object调用基础构造函数。这样就可以被MEF发现。

<强> 2。修改AutoPopulateExportedViewsBehavior

[ImportMany(typeof(UserControl))]
public Lazy<UserControl, IViewRegionRegistration>[] RegisteredViews { get; set; }

添加[ImportMany]属性,并将延迟初始化的类型更改为UserControl。现在,导入所有UserControl IViewRegionRegistration - 实现MetaData类型。

基本上就是这样。您可以像以前一样使用[ViewExport]。请注意,视图仅限于UserControl的(子)类型。我想如果你愿意,可以修改。确保您的汇总目录导入ViewExportAttributeAutoPopulateExportedViewsBehavior,正如Nicolaus所说......

这样,您不需要为视图添加其他界面,并且仍然可以在没有硬编码注册的情况下发现所有内容。

如果我错过了解决方案的任何缺点,我希望它有所帮助,让我知道。