PRISM 4 - 注册视图到区域 & 自定义导出属性

5

我正在使用带有MEF扩展和MVVM模式的Prism 4。在模块的初始化期间,我调用RegisterViewWithRegion(RegionNames.MyRegion,typeof(MyView)), 当视图构造如下时,它可以完美地工作:

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

视图被注册后一切正常。但是,只要我将Export更改为自定义导出属性,即使它仍然在容器中,视图也无法找到。这个自定义导出属性来自股票交易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,键为""的实例时发生激活错误。

有什么建议吗?我整天都在看这段代码,但没有找到解决方案。


那天晚上...我终于发现这与自定义导出属性中的这部分有关:base(typeof(object)) - 但仍然不知道如何解决RegisterViewWithRegion的问题... - okieh
4个回答

4

您是否在MEF引导程序中配置聚合目录?如果是,您是否添加了包含ViewExportAttribute和AutoPopulateExportedViewsBehavior类的程序集?我认为这在StockTraderRI的引导程序中通过以下行发生:

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

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


我遇到了与原问题提出者相同的问题,这是解决方案。 - Dylan

4
又是新的一天,新的方式...尽管我对PRISM的了解有限,但我会尝试回答我的问题。换句话说:我还在学习中。
从股票交易RI中获取的自定义导出属性被AutoPopulateExportedViewsBehavior使用。此行为通过检查区域名称的导出属性自动向其区域添加视图,然后将视图添加到相应的区域。但是,具有此自定义属性的所有视图现在都具有“对象”的契约名称,这使得ServiveLocator无法找到它们。此自定义属性适用于具有固定区域/视图链接的场景。 使用自定义导出属性时的解决方案是获取所有类型为“对象”的导出项和相应的元数据:
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]属性,这样一切都会顺利进行。


0

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

至于激活错误,您需要更详细地查看异常。根本原因可能就在那里,也许被隐藏在InnerException下面。


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]属性,并将Lazy初始化的类型更改为UserControl。现在,所有具有实现IViewRegionRegistration元数据类型的UserControl都被导入。

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

这样,您就不需要为视图添加额外的接口,仍然可以发现所有内容,而无需硬编码注册。

希望这有所帮助,如果我漏掉了任何缺点,请告诉我。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接