我正在使用带有MEF扩展和MVVM模式的Prism 4。在模块初始化期间,我调用RegisterViewWithRegion(RegionNames.MyRegion,typeof(MyView)),当视图构造为这样时,它可以完美地工作:
[Export]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class MyView : UserControl
{
public MyView()
{
....
视图已注册,一切正常。一旦我将"导出"更改为"自定义导出属性",就再也找不到视图了,尽管它仍在容器中。此自定义导出属性取自股票交易员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的实例时发生激活错误,密钥为"
有什么建议吗?我整天都在看这部分代码,却没有找到解决方案。
又是一天,又是另一种方式。。。尽管我对PRISM的了解有限,但我会尽力回答我的问题。换句话说:我还在学习。
AutoPopulateExportedViewsBehavior
使用从股票交易RI获取的自定义导出属性。此行为通过检查区域名称的"导出属性"(Export Attribute),自动将视图添加到其区域,然后将视图添加至相应的区域。但是,所有具有此自定义属性的视图现在都有一个约定名称"object",这使得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]属性,这样一切都会顺利进行。
您是否在MEF引导程序中配置聚合目录?如果是,您是否正在添加包含ViewExportAttribute和AutoPopulateExportedViewsBehavior类的程序集?我相信这发生在StockTraderRI的引导程序中,它有这样一行:
this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(StockTraderRICommands).Assembly));
StockTraderRICommands类与ViewExportAttribute和AutoPopulateExportedViewsBehavior类位于同一程序集中。
自定义导出属性将typeof(object)
传递给基构造函数,该构造函数将更改导出的协定,使其不再与导入匹配。将其更改为调用无参数构造函数。
至于激活错误,您需要更详细地查看异常。根本原因可能在某个地方,可能埋在InnerException之下。
我遇到了完全相同的问题,对于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
的(子)类型。如果你愿意的话,我想这可以修改。并确保你的聚合目录导入ViewExportAttribute
和AutoPopulateExportedViewsBehavior
,正如Nicolaus所说。。。
这样,您就不需要为视图提供额外的接口,并且仍然可以在没有硬编码注册的情况下发现所有内容。
如果我错过了解决方案的任何缺点,我希望它能帮助我,并让我知道。