将 Autofac 容器传递给 WPF UserControl

2024-01-08

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

一个例子:

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

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

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

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

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

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


我不会注入(有效的)您的容器,因为这是一种称为服务定位器的控制反转的低级形式,其缺陷可以通过您当前的情况来总结:您最终需要将容器注入到所有内容中。

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

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

例如,如果子视图需要 IFooViewModel,您可以使用 Func

(或 Func,根据您的需要)

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

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

  • 应用程序创建主窗口

  • MainWindow创建SubView1,需要IMainWindowViewModel

  • SubView1需要ISubView1Model,IFooService

  • 子视图1创建子视图2

  • SubView2需要ISubView2Model、IBarService

所以我们的演员看起来像:

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 容器最光荣的(在我看来,唯一的)用途是“你根据我已经告诉你的内容弄清楚如何获取所有位”部分 - 否则,你最好使用手动注入,在其中你手动传递依赖项。也就是说,我们潜在的复杂的 MainWindow 构造现在只是:

container.Resolve<MainWindow>();

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

将 Autofac 容器传递给 WPF UserControl 的相关文章

随机推荐

  • 将 Base64 字符串加载到画布时遇到问题

    我正在尝试将 Base64 字符串从数据库加载到画布 我通过执行相反的方法获得了这个字符串 在画布上绘制后将其保存到我的数据库中 所以 现在我想将其加载回另一个画布上 我已经尝试过在网络和 StackOverflow 上其他地方找到的这段代
  • 尝试使用 getRange 时出现类型错误

    NOTE This is a proposal of canonical Q A Please discuss it on Meta https meta stackoverflow com q 420764 1595451 作为新的 Go
  • 使用数据框架构的 Spark 地图数据框

    我有一个从 JSON 对象创建的数据框 我可以查询这个数据框并将其写入镶木地板 由于我推断了架构 因此我不一定知道数据框中的内容 有没有办法使用自己的架构来输出列名称或映射数据框 The results of SQL queries are
  • 如何检测浏览器何时在 Web 登录中输入存储的密码

    我有一个网站 可以检测何时输入用户名和密码 然后启用登录按钮 问题是 如果浏览器输入它记住的用户名和密码 则登录按钮永远不会启用 JavaScript 有没有办法检测浏览器输入此信息 你可以用以下方式进行轮询setInterval 但是为什
  • 如何将 Invoke-RestMethod 的响应转换为 XML?

    参考help https learn microsoft com en us powershell module microsoft powershell utility invoke restmethod view powershell
  • 将 URL 参数传递到 HTML 表单 Google Web App

    我已经浏览了大部分与此相关的问题 但没有找到对我有帮助的解决方案 我已经一一应用了它们 我有一个 HTML 表单 我正在通过 google 将其发布为网络应用程序 我需要用该参数预先填充输入框 code gs function doGet
  • 为什么 March=native 会破坏我的程序?

    我正在编译程序 include
  • 如何让liveserver渲染django模板?

    我一直在搞一个教程网站 我发现当我尝试打开 Django 模板时 我的 VS Code LiveServer 插件无法正常工作 我应用的 CSS 丢失了 尽管一切都在我的本地开发服务器中正确呈现 并且模板语言代码实际上被打印到屏幕上而不是被
  • 如何创建/管理作业队列[重复]

    这个问题在这里已经有答案了 我有一个有序列表中包含数千个 shell 作业的队列 我需要从上到下并行运行 4 个作业以避免 CPU 饱和 如果我只是将作业列表拆分为 4 个批处理脚本 则运行时不会对齐 其中一个脚本将远远领先于其他脚本 但仍
  • STOMP 或 XMPP - 通过 websocket

    我正在开发一个涉及实时聊天 消息传递 包括群聊 的项目 我以前使用过 websockets 所以我开始使用 spring websockets 来研究这个问题 并且我阅读了一些关于实现它的最佳方法的文章 然后我遇到了 STOMP 作为 we
  • 使用 Capistrano,如何回滚到特定版本?

    使用 Capistrano 如何回滚到特定版本 我的服务器文件夹中有一个 release 文件夹 我如何回滚到特定的文件夹 我是否可以在本地计算机上获取版本列表 我正在使用 GIT 但这不起作用 cap deploy s revision
  • 打字稿“不是索引器的子类型”,是什么意思?

    我正在通过阅读来学习 Typescript这份官方文件 https www typescriptlang org docs handbook interfaces html关于索引器类型 我无法理解这段代码 interface Number
  • 大范围连续整数的数据结构?

    假设内存中有大量连续整数 每个整数都属于一个类别 两个操作必须是 O log n 将范围从一个类别移动到另一个类别 以及查找给定范围的类别计数 我很确定只要第一个操作的正确实现 第二个操作就可以轻松解决 每个整数都从一个类别开始 因此我从一
  • 带凭证的 AngularJS

    我一直在开发一个 AngularJS 项目 该项目必须将 AJAX 调用发送到 Restfull Web 服务 该网络服务位于另一个域中 因此我必须在服务器上启用 cors 我通过设置这些标头来做到这一点 cresp getHttpHead
  • 在 bash 中仅杀死管道中的第一个进程

    如果我有一个长时间运行的命令定期输出一些数据 例如tail F我想用 awk 或其他东西 处理 tail F service log awk END print How to kill the first process only tail
  • 二进制响应内容,请求库

    我正在阅读有关请求库的文档 它似乎已经非常过时了 我一步一步尝试了其中显示的所有示例 并在尝试运行以下代码时遇到了问题 import requests from PIL import Image from StringIO import S
  • 现有 ASP.NET 4 解决方案中的高效 URL 屏蔽/伪装/隐藏

    我当前的系统使用 IIS 6 和 7 使用 ASP NET 和 NET 4 中的 C 编写 我的目的是完全隐藏网址 根据客户请求 IE https myapp it mydomain com Secure folder1 folder2 f
  • 正则表达式匹配 Perl 中字符串的第二次出现

    我正在尝试匹配 perl 中字符串的第一次和第二次出现 输入的前几行 包含在 intersect 中 是 gi 112807938 emb CU075707 1 Xenopus tropicalis finished cDNA clone
  • 无法打开活动:无法创建 Android 视图模型实例

    我正在创建一个应用程序来扫描条形码并使用 Android 视图模型和 LiveData 将该信息获取到房间数据库中 这是错误消息 java lang RuntimeException Unable to start activity Com
  • 将 Autofac 容器传递给 WPF UserControl

    我正在使用 autofac 来解析 WPF 应用程序中的视图和视图模型 IComponentContext 自动传递到视图中 一个例子 public BusinessAuto int proposedCoverageId IComponen