最近我开始将我的一个项目重新组织成更小的程序集。在一个步骤中,我将视图和视图模型移动到单独的程序集中,同时将视图和VM保持在一个通用程序集中。因此我的项目结构如下:
命名空间是这样的:
"主"包含bootstrapper和d minimalistic vm以及用于选择模块的视图。每个演示者都包含该演示者所需的所有视图和视图模型。 "核心"包含文件夹中每个项目使用的资产(例如元数据定义,导出接口等)
现在移动后,Caliburn.Micro找不到视图模型的视图,无论它多么简单。以下是视图模型和视图的示例:
namespace RpgTools.LocationPresenter.ViewModels
{
using System.ComponentModel.Composition;
using RpgTools.Core.Contracts;
[RpgModuleMetadata(Name = "Module C")]
[Export(typeof(IRpgModuleContract))]
public class ModuleCViewModel :IRpgModuleContract
{
}
}
<UserControl x:Class="RpgTools.LocationPresenter.Views.ModuleCView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock Text="ModuleC" />
</Grid>
</UserControl>
每次加载模块时都会出现以下错误:
无法找到RpgTools.LocationPresenter.ViewModels.ModuleCViewModel的视图。
如果我将模型移回&#34; Main&#34;它工作得很好。因为它可能是引导程序的一部分,所以它的完整代码是:
namespace RpgTools.Main
{
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows;
using Caliburn.Micro;
using RpgTools.Core.Contracts;
/// <summary>The MEF bootstrapper.</summary>
[SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1650:ElementDocumentationMustBeSpelledCorrectly", Justification = "Reviewed. Suppression is OK here.")]
public class MefBootstrapper : BootstrapperBase
{
/// <summary>The composition container.</summary>
private CompositionContainer compositionContainer;
/// <summary>Initialises a new instance of the <see cref="MefBootstrapper"/> class.</summary>
public MefBootstrapper()
{
// this.CheckModuleDirectory();
this.Initialize();
}
/// <summary>Override to configure the framework and setup your IoC container.</summary>
protected override void Configure()
{
// Get the modules from the module directory
// ToDo: Implement dynamic loading from modules directory.
DirectoryCatalog dirCatalog = new DirectoryCatalog(@".");
// Create a combinable catalog
// ReSharper disable once RedundantEnumerableCastCall
AggregateCatalog catalog = new AggregateCatalog(AssemblySource.Instance.Select(s => new AssemblyCatalog(s)).OfType<ComposablePartCatalog>());
catalog.Catalogs.Add(dirCatalog);
// Create a new composition container.
// ReSharper disable once RedundantEnumerableCastCall
this.compositionContainer = new CompositionContainer();
// Create a new composition container.
this.compositionContainer = new CompositionContainer(catalog);
CompositionBatch compositionBatch = new CompositionBatch();
// Add window manager to composition batch.
compositionBatch.AddExportedValue<IWindowManager>(new ToolsWindowManager());
// Add EventAggregator to composition batch.
compositionBatch.AddExportedValue<IEventAggregator>(new EventAggregator());
// Add the container itself.
compositionBatch.AddExportedValue(this.compositionContainer);
// Compose the container.
this.compositionContainer.Compose(compositionBatch);
}
/// <summary>Override this to provide an IoC specific implementation.</summary>
/// <param name="service">The service to locate.</param>
/// <param name="key">The key to locate.</param>
/// <returns>The located service.</returns>
protected override object GetInstance(Type service, string key)
{
// Check if the contract is null or an empty string, if so return the contract name from the service itself.
string contractName = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(service) : key;
// Get a collection of exported values with the goven contract name.
IList<object> exports = this.compositionContainer.GetExportedValues<object>(contractName).ToList();
if (exports.Any())
{
return exports.First();
}
throw new Exception(string.Format("Could not locate any instances of contract {0}.", contractName));
}
/// <summary>Override this to provide an IoC specific implementation</summary>
/// <param name="serviceType">The service to locate.</param>
/// <returns>The located services.</returns>
protected override IEnumerable<object> GetAllInstances(Type serviceType)
{
return this.compositionContainer.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
}
/// <summary>Override this to provide an IoC specific implementation.</summary>
/// <param name="instance"> The instance to perform injection on.</param>
protected override void BuildUp(object instance)
{
this.compositionContainer.SatisfyImportsOnce(instance);
}
/// <summary>Override this to add custom behaviour to execute after the application starts.</summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The args.</param>
protected override void OnStartup(object sender, StartupEventArgs e)
{
this.DisplayRootViewFor<IShell>();
}
/// <summary>Checks if the modules directory exists and if not create it.</summary>
private void CheckModuleDirectory()
{
if (!Directory.Exists(@".\Modules"))
{
Directory.CreateDirectory(@".\Modules");
}
}
}
}
我可能会补充说模块发现工作正常。我的ShellView模型显示我添加的每个项目中的每个模块都很好,如果视图位于与#34; Main&#34;
不同的程序集中,则视图的加载不起作用。我通过使用以下代码覆盖SelectAssemblies()
方法修复了原始问题:
protected override IEnumerable<Assembly> SelectAssemblies()
{
var assemblies = Directory.GetFiles(ModuleDirectory, "*.dll", SearchOption.AllDirectories).Select(Assembly.LoadFrom).ToList();
assemblies.Add(Assembly.GetExecutingAssembly());
return assemblies;
}
然而现在我的所有模块都被加载了两次!这是我所做代码中唯一的变化。我做错了什么?
答案 0 :(得分:8)
您需要覆盖SelectAssemblies
中的Bootstrapper
以包含包含您的视图的程序集。默认情况下,Caliburn Micro仅包含Bootstrapper
定义的程序集。
那么,AssemblySource.Instance是什么?这是Caliburn.Micro寻找视图的地方。您可以在应用程序期间随时向其添加程序集,以使它们可供框架使用,但在Bootstrapper中还有一个特殊的位置。只需覆盖这样的SelectAssemblies:
protected override IEnumerable<Assembly> SelectAssemblies()
{
return new[] {
Assembly.GetExecutingAssembly()
};
}
您所要做的就是返回一个可搜索的程序集列表。默认情况下,基类返回应用程序所在的程序集。因此,如果所有视图与应用程序位于同一程序集中,则甚至不必担心这一点。如果您有多个包含视图的引用程序集,则这是您需要记住的扩展点。