Caliburn.Micro Bootstrapper及IOC容器配置

Caliburn.Micro Bootstrapper及IOC容器配置如果想深入学习Caliburn.Micro,Bootstrapper和IOC容器配置是重中之重,一定要弄清楚,否则很难理解CM的工作方式。配置Bootstrapper的意义如果在Boostrapper中不进行任何配置的话,Bootstrapper会首先把Bootstrapper所在程序集加载到AssemblySource.Instance中。而我们在Bootstrapper中只在Displa…

大家好,又见面了,我是你们的朋友全栈君。

如果想深入学习Caliburn.Micro,Bootstrapper和IOC容器配置是重中之重,一定要弄清楚,否则很难理解CM的工作方式。

配置Bootstrapper的意义

如果在Boostrapper中不进行任何配置的话,Bootstrapper会首先把Bootstrapper所在程序集加载到 AssemblySource.Instance中。而我们在Bootstrapper中只在DisplayRootViewFor()中给定了一个主ViewModel的类型,那么CM是如何找到找到ViewModel和View并创建实例的?

CM获得ViewModel实例的方式

CM查找ViewModel的方式只有一个,就是从IOC中提取。默认提取方法是IOC.GetInstance,这个方法是直接用ViewModel的类型创建ViewModel的实例,即Activator.CreateInstance()。默认的IOC.GetInstance方法,多次调用就相当于是多次创建新实例,实际上我们只需要第一次是创建新实例,再次调用,只需要返回已经有的实例就ok了。默认的方式是一个很简单的让CM能正常工作的方式,但不是很好,建议用户还是使用自定义的IOC容器。

并且,默认的方式有如下缺点:

  1. Bootstrapper需要依赖ViewModel所在的程序集,否则IOC无法创建ViewModel实例。
  2. 每次从IOC提取实例都是一个新建的实例,无法找到之前创建的实例。

这些问题都可以通过配置MEF等作为IOC容器后解决。

CM获得View实例的方式

在配置IOC容器之前,我们先看看,CM获取实例的方式。清楚的知道CM在内部是如何使用IOC的,才能更好的配置IOC。

CM在创建ViewModel实例后,会先根据ViewModel类型全名获取View的类型名(根据设定的名称映射规则),然后根据View的类型名查找View类型并创建实例。CM会在3个地方查找View,如下:

  1. ViewAware:仅仅只有ViewModel继承了ViewAware,并且View实例已经被创建之后才能用。如果一个ViewModel继承自ViewAware,那么在创建ViewModel对应的View时,会调用ViewAware的AttachView方法把View关联在ViewModel上,以后就可以通过ViewAware的GetView方法获得关联的View。也就是说从ViewAware只能获取已有的View实例,并不能创建View实例。ViewModel可以通过继承Screen的方式间接继承ViewAware(Screen继承了ViewAware),这样会有很多方便,比如在ViewModel中用GetView获得View进行某些操作。
  2. AssemblySource:用FindTypeByNames方法可以从AssemblySource.Instance中根据类型名称获取类型,然后CM用得到的类型创建View实例。AssemblySource.Instance中的类型都是Bootstrapper的SelectAssemblies方法提供的,在Bootstrapper中可以重载SelectAssemblies方法。
  3. IOC:默认情况下没有配置IOC容器,只是在IOC.GetInstance方法中提供了一个简单的创建实例的方法。

所以如果没有配置IOC容器的话,View所在程序集就必须满足以下之一:

  • 用SelectAssemblies方法加载到AssemblySource中。这样CM就可以从AssemblySource中获取View类型
  • View和Bootstrapper在同一个程序集。这样CM就可以用默认IOC.GetInstance静态方法创建一个View实例。

Bootstrapper配置内容

Bootstrapper中有2个必需用的方法即:

  • Initialize:初始化Bootstrapper所有设置,包括EventAggregator事件、AssemblySource、IOC、Application事件。
  • DisplayRootViewFor: 显示主界面。

Bootstrapper中可以通过重载来配置CM的方法主要有:

  • SelectAssemblies() :设置加载到AssemblySource中的程序集列表

  • PrepareApplication():从名字就可以看出是application的事件处理,事实上里边代码是这样的

      Application.Startup += OnStartup;
      Application.DispatcherUnhandledException += OnUnhandledException;
      Application.Exit += OnExit;
    

    所以,OnStartup(object sender, StartupEventArgs e)、OnExit(object sender, EventArgs e)、OnUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e) 这3个可以重载的方法意义就很清楚了

  • Configure(): 用于配置IOC容器

  • GetInstance(Type service, string key):IOC容器获取实例的方法

  • GetAllInstances(Type service):IOC容器获取实例的方法

  • BuildUp(object instance) :IOC容器注入实例的方法

Bootstrapper配置实例

MEF是一个.net的插件框架,也可以作为一个依赖注入容器(IOC)使用。我通常就用MEF作为CM的IOC容器。在MEF中所有export部件都会被作为插件导入到container中,通过container也可以访问每个export对象。我们在把MEF作为IOC容器的时候,通常只需要把类标记为export导入到container就可以了,当然不标记为export的类是无法导入到container的。也就是说我们把MEF作为IOC容器的时候,主要使用export部件相关的功能。不了解MEF的话,请了解一下MEF再看以下内容会比较容易理解。

AssemblySource配置

AssemblySource在CM中只有在查找View的时候会用到,(当然ViewModel-First的时候查找ViewModel也会用到)。所以如果你把View和ViewModel都注入到IOC容器中,应该是可以不需要AssemblySource的。事实上我们在用MEF作为IOC容器时一般只把ViewModel导入容器,View不作处理的。所以,一定要记得把View所在的程序集加入到AssemblySource。

代码示例如下:

protected override IEnumerable<Assembly> SelectAssemblies()
{ 
   
    return new[] { 
   
        Assembly.GetExecutingAssembly()
    };//返回目前正在執行程序集,当View在目前正在执行的程序集中时,可以这样写。
}

我个人习惯吧View单独放在一个文件夹的不同程序集中,所以我通常是这样做的:

        protected override IEnumerable<Assembly> SelectAssemblies()
        { 
   
            List<Assembly> lst = new List<Assembly>();
            lst.AddRange(base.SelectAssemblies());
            lst.AddRange(
                Directory.GetFiles(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location) + @"\views")
                    .Where(file => file.EndsWith("dll", true, CultureInfo.CurrentCulture) || file.EndsWith("exe", true, CultureInfo.CurrentCulture))
                    .Select(Assembly.LoadFrom));
            //lst.AddRange(from file in Directory.GetFiles(Environment.CurrentDirectory + @"\views") where file.EndsWith("dll") || file.EndsWith("exe") select Assembly.LoadFrom(file));
            return lst;
        }

虽然并不需要把ViewModel部分也加载到AssemblySource中,但是建议还是放进去比较好,这样在使用的时候会比较方便,并且IOC容器也可以直接用AssemblySource里的内容填充。

如果动态加载了模块,也建议能够同时在AssemblySource和IOC中注册模块。

IOC配置

在这里我们用MEF作为IOC容器,所以需要先引用两个命名空间:

using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;

如果所有需要注入IOC的类都已经导入到了AssemblySource,就可以这样设置IOC。注:ViewModel-First时,ViewModel是必需要注入到IOC的。

    protected override void Configure()
    { 
   
        container = CompositionContainer(
            new AggregateCatalog(   AssemblySource.Instance.Select(x => new AssemblyCatalog(x))  )
            );

        var batch = new CompositionBatch();
        batch.AddExportedValue<IWindowManager>(new WindowManager());//新建一个窗口管理器添加到IOC中
        batch.AddExportedValue<IEventAggregator>(new EventAggregator());//如果要使用弱事件就需要添加这个了
        batch.AddExportedValue(container);//只是个习惯,这样就可以在任何地方通过IOC使用container了
        container.Compose(batch);
    }

从IOC容器中获取对象的方法代码如下:

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

        var exportList = exports.ToList();//避免直接用exports时 调用2次IEnumerable操作
        if (exportList.Any())
            return exportList.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);
    }

BuildUp用到的不多,可以不设置。

Application相关配置

PrepareApplication()中,我们可以添加新的事件处理程序,比如Activated等。OnStartup可以添加程序启动前需要处理的事情,比如命令行参数处理等,当然还有DisplayRootViewFor方法。OnUnhandledException中添加程序中未处理的异常的处理方法。OnExit处理程序退出事件。

另外,在其他平台(非PC)及winform中应用略有不同,请查看官方帮助。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/162197.html原文链接:https://javaforall.net

(0)
上一篇 2022年7月20日 上午11:16
下一篇 2022年7月20日 上午11:16


相关推荐

  • 多层感知器速成

    多层感知器速成转载自 深度学习 基于 Keras 的 Python 实践 第四章魏贞原著电子工业出版社微信文章地址 https mp weixin com s WWuKIE4ZGD3K 人工神经网络是一个引人入胜的学习领域 尽管在开始学习的时候非常复杂 本章将会快速的介绍一下在人工神经网络领域使用的多层感知器 4 1 多层感知器人工神经网络领域通常被称为神经网络或多层感知器 MLP MultilayerPe 多层感知器也许是最有用的神经网络类型 多层感知器是一种前馈

    2026年3月26日
    1
  • 软测试总结

    软测试总结

    2022年1月12日
    45
  • mybatiscodehelperpro激活码【2021.10最新】

    (mybatiscodehelperpro激活码)2021最新分享一个能用的的激活码出来,希望能帮到需要激活的朋友。目前这个是能用的,但是用的人多了之后也会失效,会不定时更新的,大家持续关注此网站~IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html…

    2022年3月28日
    989
  • 培训java机构排行榜_北京java培训班哪家好

    培训java机构排行榜_北京java培训班哪家好要说国内的就业市场中,薪资高待遇好的当属Java软件开发岗位了,因Java软件开发的职业发展稳定获得了不少从业者的追捧。对于想要学习Java的同学来说,培训就成了进入这个行业的敲门砖,很多零基础不太懂这个行业的同学,想要找一家比较好的培训机构,都会在网络上搜索一些像“北京Java培训机构排名”这样的词,能够在其中得到一些参考,下面是通过行业口碑,Java就业率,诚信度,课程体系,Java师资,教学质量,授课方式等多方面得出的北京Java培训机构排名,参考意义很强。就算我们有了排名上的参考,也需.

    2022年10月3日
    6
  • redis查看所有key-value对

    redis查看所有key-value对如题 使用 kyes 命令模糊匹配 rediskeys 1 aaa 2 mytestmap 3 jredis examples HelloAgain message 4 testbean 5 foo rand00000000 6 test 7 jredis

    2026年3月16日
    2
  • 表单编号和文件编号_php制作一个表单

    表单编号和文件编号_php制作一个表单在实际的编程中,表单的HTML代码和获取表单的PHP程序可以分别写到两个文件中,也可以写到同一个PHP文件中。初学Web交互编程时,为了简便,可以使用后者,因为这样做可以减少网站内网页文件的数量。

    2022年8月11日
    8

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号