我不确定如何连接Caliburn.Micro以使用PCL版本的MEF2。我已经看过MefBootstrapper example,但是它使用了许多无法使用的课程,而且我无法转换为新的API。
这是我到目前为止所拥有的:
using System;
using System.Collections.Generic;
using System.Composition;
using System.Composition.Hosting;
using System.Linq;
using Caliburn.Micro;
namespace Test
{
public class Bootstrapper : BootstrapperBase
{
private CompositionHost _host;
public Bootstrapper()
{
Initialize();
}
protected override void Configure()
{
var config = new ContainerConfiguration();
config.WithAssemblies(AssemblySource.Instance);
// batch.AddExportedValue<IWindowManager>(new WindowManager());
// batch.AddExportedValue<IEventAggregator>(new EventAggregator());
// batch.AddExportedValue(container);
_host = config.CreateContainer();
}
protected override object GetInstance(Type serviceType, string key)
{
string contract = string.IsNullOrEmpty(key) ? serviceType.ToString() : key;
var exports = _host.GetExports<object>(contract).ToArray();
if (exports.Any())
return exports.First();
throw new Exception(string.Format("Could not locate any instances of contract {0}.", contract));
}
protected override IEnumerable<object> GetAllInstances(Type serviceType)
{
return _host.GetExports<object>(serviceType.ToString());
}
protected override void BuildUp(object instance)
{
_host.SatisfyImports(instance);
}
protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
{
DisplayRootViewFor<IShell>();
}
}
}
但是,CompositionHost似乎没有任何导出,我不知道如何向它添加对象(WindowManager和EventAggregator)。
答案 0 :(得分:1)
稍微玩了一下,这就是我想出来的东西,似乎有效:
[Export(typeof(IWindowManager))]
public class MyWindowManager : WindowManager
{
}
[Export(typeof(IEventAggregator))]
public class MyEventAggregator : EventAggregator
{
}
public interface IShell
{
}
public class AppBootstrapper : BootstrapperBase
{
private CompositionHost _host;
public AppBootstrapper()
{
Initialize();
}
protected override IEnumerable<Assembly> SelectAssemblies()
{
// TODO: Add additional assemblies here
yield return typeof(AppBootstrapper).GetTypeInfo().Assembly;
}
protected override void Configure()
{
var config = new ContainerConfiguration();
var assemblies = AssemblySource.Instance.Union(SelectAssemblies());
config.WithAssemblies(assemblies);
_host = config.CreateContainer();
}
protected override object GetInstance(Type serviceType, string key)
{
var exports = _host.GetExports(serviceType, key).ToArray();
if (exports.Any())
return exports.First();
throw new Exception(string.Format("Could not locate any instances of contract {0}.", serviceType.Name));
}
protected override IEnumerable<object> GetAllInstances(Type serviceType)
{
return _host.GetExports<object>(serviceType.ToString());
}
protected override void BuildUp(object instance)
{
_host.SatisfyImports(instance);
}
protected override void OnStartup(object sender, System.Windows.StartupEventArgs e)
{
DisplayRootViewFor<IShell>();
}
}
答案 1 :(得分:0)
mine is certainly a late reply, but maybe this is helpful to someone else struggling with the poor MEF2 docs, and surely it might help me too, if anyone comes up with better implementations, or finds any issues in this solution; so here it is.
For a less attribute-oriented approach (which is one of the essential MEF2 features), and to avoid the hack of wrapping the CM injectables into custom classes, you must configure the assemblies exports, as follows:
protected override IEnumerable<Assembly> SelectAssemblies()
{
return new[]
{
typeof (IEventAggregator).GetTypeInfo().Assembly,
typeof (IWindowManager).GetTypeInfo().Assembly,
typeof (MefBootstrapper).GetTypeInfo().Assembly
};
}
protected override void Configure()
{
var config = new ContainerConfiguration();
// note that the event aggregator is in the core CM assembly,
// while the window manager in the platform-dependent CM assembly,
// so that we need 2 conventions for 2 assemblies.
ConventionBuilder cmBuilder = new ConventionBuilder();
cmBuilder.ForType<EventAggregator>().Export<IEventAggregator>();
ConventionBuilder cmpBuilder = new ConventionBuilder();
cmpBuilder.ForType<WindowManager>().Export<IWindowManager>();
ConventionBuilder appBuilder = new ConventionBuilder();
appBuilder.ForTypesMatching(t =>
t.Name.EndsWith("ViewModel", StringComparison.OrdinalIgnoreCase)).Export();
appBuilder.ForType<MainViewModel>().Export<IShell>();
config.WithAssembly(typeof(IEventAggregator).GetTypeInfo().Assembly, cmBuilder);
config.WithAssembly(typeof(IWindowManager).GetTypeInfo().Assembly, cmpBuilder);
config.WithAssembly(typeof(MefBootstrapper).GetTypeInfo().Assembly, appBuilder);
_host = config.CreateContainer();
}
Essentially, you must pay attention to a couple of things:
Caliburn.Micro.Platform
one.EventAggregator
as the implementation to be selected for the interface IEventAggregator
, and similarly for the window manager; further, I'm exporting my main view model as the implementation for the IShell
interface, and all the viewmodels by exporting all the classes from my app assembly whose name ends with ViewModel
. This way, I do not require any ExportAttribute
.