gpt4 book ai didi

c# - 将 Autofac 容器传递给 WPF UserControl

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

我正在使用 autofac 解析 WPF 应用程序中的 View 和 View 模型。 IComponentContext 被自动传递到 View 中。

一个例子:

    public BusinessAuto(int proposedCoverageId, IComponentContext componentContext)
{
DataContext = componentContext.Resolve<BusinessAutoViewModel>(new TypedParameter(typeof(Int32), proposedCoverageId));
InitializeComponent();
}

在此 View 的 XAML 中,创建了具有自己的 ViewModel 的 UserControl。一个例子:

<userControl:AdditionalCoveragesControl Margin="0,10"/>

Autofac 没有创建 UserControl(View 是),因此 Autofac 无法将依赖项注入(inject)到 UserControl 的构造函数中。

如何将对 IComponentContext 的引用获取到在初始 View 的 XAML 中声明的 UserControl 中?

我觉得我要么需要 Autofac 以某种方式创建我的 UserControl,要么我需要恢复到气馁的全局静态容器(恶心),要么我必须使用 DependencyProperty 向下传递容器(也恶心)。

最佳答案

我不会注入(inject)(有效的)您的容器,因为这是一种劣质的控制反转形式,称为服务定位器,其缺陷可以总结为您当前的情况:您最终需要注入(inject)容器融入一切。

相反,您需要从“这个组件负责创建什么,它需要做什么?”的角度来处理问题。

正如 Lonni-Loki 所提到的,一种选择是注入(inject)一个完全形成的控件,但我不同意这一点:如果主视图有责任创建这个子组件,那么它应该创建它 - 但为了促进这一责任,您应该将主视图与服务/模型/等一起注入(inject),然后它需要传递或以其他方式用于创建它。 Autofac 的工厂方法 stub 非常适用于此:

例如,如果 subview 需要一个 IFooViewModel,您可以使用 Func

(或 Func ,根据您的需要)

一个方便的经验法则是在考虑类 X 时,首先在任何地方“新建”任何东西,而不是将其传递给构造函数。现在看看代码并问问自己“如果我想要一个类 X 的实例,我需要传递给构造函数什么?”这些是您的依赖项。

让我们举一个更实际的例子......假设你有一个这样的结构:

  • 应用程序创建主窗口

  • MainWindow 创建 SubView1,需要 IMainWindowViewModel

  • SubView1 需要 ISubView1Model、IFooService

  • SubView1 创建 SubView2

  • SubView2 需要 ISubView2Model、IBarService

所以我们的 ctors 看起来像:

public MainWindow(IMainWindowViewModel viewModel, 
Func<SubView1> subView1Factory)

public SubView1(ISubView1Model viewModel,
IFooService fooService,
Func<IFooService, SubView2> subView2Factory)

public SubView2(
ISubView2ModelViewModel viewModel,
IBarService barService)

当设置你的容器时,你会有这样的东西:

(注意,我使用了多种 IoC 容器,所以我的 Autofac 语法可能生锈了)

var builder = new ContainerBuilder();

// Simple bit, register implementations for viewmodel, services
builder.RegisterType<MainWindowViewModel>.As<IMainWindowViewModel>();
builder.RegisterType<SubView1Model>.As<ISubView1Model>();
builder.RegisterInstance<FooService>.As<IFooService>();

// ok, lemme see if I can remember expression syntax...

// Simple case: 'static' resolution of subview
// We want a func that takes no args and returns us a fully-initialized
// SubView1
builder.Register<Func<SubView1>>(context =>
{
// Since all the bits of a subview1 are registered, simply
// resolve it and return
var view = context.Resolve<SubView1>();
return () => view;
});

// Complicated case - lets say this viewmodel depends
// on foo service, which it uses to determine which
// bar service to use
builder.Register<Func<IFooService, SubView2>>(context =>
{
// and our view model
var vm = context.Resolve<ISubView2ViewModel>();

return (service) =>
{
var barService = new BarService(service);
return new SubView2(vm, barService);
};
});

用于 IoC 容器的光荣(并且在我看来,唯一)是“你想出如何根据我已经告诉你的内容获取所有位”部分 - 否则,你还不如使用手动注入(inject),您可以在其中手动传递依赖项。也就是说,我们可能复杂的 MainWindow 构造现在只是:

container.Resolve<MainWindow>();

我希望我没有在代码中犯太多错别字/错误,但我已经有一段时间没有使用 Autofac 了。

关于c# - 将 Autofac 容器传递给 WPF UserControl,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13845903/

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