gpt4 book ai didi

c# - WPF Caliburn MEF 应用程序和 DI

转载 作者:行者123 更新时间:2023-11-30 14:23:34 25 4
gpt4 key购买 nike

我正在尝试在 WPF 应用程序中使用 Caliburn 和 MEF。我的 MEF 知识充其量只是粗略的。

这是 Bootstrap :

class Bootstrapper : BootstrapperBase
{
public Bootstrapper()
{
Initialize();
}

protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<IShell>();
}

protected override void Configure()
{
//An aggregate catalog that combines multiple catalogs
var catalog = new AggregateCatalog();

//Adds all the parts found in the same assembly as the Program class
catalog.Catalogs.Add(new AssemblyCatalog(typeof(Bootstrapper).Assembly));

//Create the CompositionContainer with the parts in the catalog
container = new CompositionContainer(catalog);

var batch = new CompositionBatch();
batch.AddExportedValue<IWindowManager>(new WindowManager());
batch.AddExportedValue<IEventAggregator>(new EventAggregator());
batch.AddExportedValue(container);

container.Compose(batch);
}

protected override object GetInstance(Type serviceType, string key)
{
string contract = string.IsNullOrEmpty(key) ? AttributedModelServices.GetContractName(serviceType) : key;
var exports = container.GetExportedValues<object>(contract);

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 container.GetExportedValues<object>(AttributedModelServices.GetContractName(serviceType));
}

protected override void BuildUp(object instance)
{
container.SatisfyImportsOnce(instance);
}

这是 shellview:

<Window x:Class="MefCaliburn.ShellView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MefCaliburn"
mc:Ignorable="d"
Title="ShellView" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20"/>
<RowDefinition/>
<RowDefinition Height="100"/>
</Grid.RowDefinitions>

<ContentControl Grid.Row="0" x:Name="Menu"></ContentControl>
<ContentControl Grid.Row="1"></ContentControl>
<ContentControl Grid.Row="2" x:Name="Messages"></ContentControl>

</Grid>

IShell 接口(interface):

public interface IShell
{
}

这是我的 shell View 模型:

namespace MefCaliburn
{
[Export(typeof(IShell))]
public class ShellViewModel : PropertyChangedBase, IShell
{
private readonly IEventAggregator _events;

UserViewModel uvm;

[ImportingConstructor]
public ShellViewModel(MenuViewModel menu, MessagesViewModel mess, IEventAggregator eventaggregator)
{
Messages = mess;
Menu = menu;
_events = eventaggregator;
}

public MessagesViewModel Messages
{
get; set;
}

public MenuViewModel Menu
{
get; set;
}

public void LaunchUserViewModel()
{
uvm = new UserViewModel();
}
}
}

所以当Boostrapper重载方法时

  protected override void OnStartup(object sender, StartupEventArgs e)
{
DisplayRootViewFor<IShell>();
}

被调用,我的 ShellViewModel 构造函数被调用,MenuMessages View 模型被注入(inject)。这是一个依赖注入(inject)的例子,对吗?

在我的例子中,菜单和消息 View 模型是与 shell 一起创建的。但是如果一个新的 View 模型

[Export(typeof(UserViewModel))]
public class UserViewModel : PropertyChangedBase
{
private readonly IEventAggregator _events;

[ImportingConstructor]
public UserViewModel(IEventAggregator eventaggregator)
{
_events = eventaggregator;
}
}

当用户按下 MenuView.xaml 上的按钮时创建

<UserControl x:Class="MefCaliburn.MenuView"
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"
xmlns:local="clr-namespace:MefCaliburn"
xmlns:cal="http://www.caliburnproject.org"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<StackPanel Orientation="Horizontal">
<Button Content="ONE" cal:Message.Attach="[Event Click] = [Action LaunchUserViewModel()]"></Button>
<Button Content="TWO"></Button>
</StackPanel>
</Grid>

UserViewModel 将向 MessagesViewModel 发布事件,我将需要 IEventAggregator。是的,我可以将它显式传递给构造函数,但我想了解的是为什么 MEF 不会注入(inject)它。

我是否尝试以非预期的方式使用 MEF? MEF 是否仅在应用程序启动时用于那些已知需要的 View 模型?

最佳答案

你有点糊涂了。首先,我认为你真的不想使用 MEF首先,但我稍后会谈到。您尝试在 LaunchUserViewModel 中创建一个新的 View 模型. MEF的整体思路|和 Dependency Injection是摆脱它。正如你在这里看到的new UserViewModel()当您尝试创建一个新实例时,您必须提供所有必需的参数。但整个想法是让框架完成工作并为我们提供它们。所以首先我们必须摆脱 new关键字并考虑以不同的方式实例化它。让我们看看您的示例:

没关系。您导出某种类型的模块。

[Export(typeof(IUserViewModel))]
public class UserViewModel : PropertyChangedBase
{
private readonly IEventAggregator _events;

[ImportingConstructor]
public UserViewModel(IEventAggregator eventaggregator)
{
_events = eventaggregator;
}
}

public interface IUserViewModel {
void SomeMethod();
}

那么我们在导出东西的时候一般会怎么做呢?我们将其导入其他地方:

[Export(typeof(IShell))]
public class ShellViewModel : PropertyChangedBase, IShell
{
[Import]
public IUserViewModel Uvm { get; set; }

public void LaunchUserViewModel()
{
Uvm.SomeMethod(); // Your Uvm is already created
}
}

如您所见,我们已完成删除 new关键词。这意味着 ShellViewModel不知道它将导入什么类。这就是它的美妙之处。您可以随时交换实现,而不必更改 ShellViewModel这里发生的是 AddExportedValue<IEventAggregator>(new EventAggregator());通知MEF ,嘿,这是一个可能想要的类。稍后当你做 [ImportingConstructor] , MEF查找构造函数需要的类,如果有,它会为您注入(inject)它们。

现在,我想你只是想要 Dependency Injection并进入了错误的框架。虽然MEF允许您使用 DI ,它更强大。它使用模块的概念,以便您可以构建模块化应用程序。当您希望允许人们为您的应用程序编写插件时,它非常有用。

它看起来像:您只会向插件显示您希望它们显示的内容,因此您将创建一个名为 API 的项目。这将只存储契约(Contract)(接口(interface))。然后你会有你程序的Core用户会提供 Plugins .用户只会看到 API , 不是 Core ,你会加载他们的插件,知道他们实际上实现了 API您告诉他们要实现的接口(interface)。

你不需要MEF使用 Dependency Injection . Caliburn.Micro已内置容器,但您也可以使用 Simple Injector , Ninject ,还有更多。

我希望这是有道理的。这是一个庞大的主题。

编辑:

我创建了一个非常基本的 project 使用Caliburn.Micro依赖注入(inject)。也许它会帮助您更好地理解它。

关于c# - WPF Caliburn MEF 应用程序和 DI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44784746/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com