温馨提示:
1. 部分包含数学公式或PPT动画的文件,查看预览时可能会显示错乱或异常,文件下载后无此问题,请放心下载。
2. 本文档由用户上传,版权归属用户,汇文网负责整理代发布。如果您对本文档版权有争议请及时联系客服。
3. 下载前请仔细阅读文档内容,确认文档内容符合您的需求后进行下载,若出现内容与标题不符可向本站投诉处理。
4. 下载文档时可能由于网络波动等原因无法下载或下载错误,付费完成后未能成功下载的用户请联系客服处理。
网站客服:3074922707
WPF_MVVM
框架
实现
IOC
依赖
注入
一种
方法
颜杰
数据库系统设计Database System Design电子技术与软件工程Electronic Technology&Software Engineering186WPF(Windows Presentation Foundation)是微软推出的基于Windows 的用户界面框架,属于.NET Framework 3.0 的一部分。它提供了统一的编程模型、语言和框架,WPF 首次提出了 MVVM(Model,View,ViewModel)设计模式,真正做到了分离界面设计人员与开发人员的工作;同时它提供了全新的多媒体交互用户图形界面。MVVM设计模式是 WPF 应用的核心理念,IOC 的概念以及容器的使用在 WPF 应用程序 MVVM 模式开发中好处众多,但 C#WPF 框架中并没有自带原生的 IOC 容器提供使用。所以一般在项目搭建初期,预先搭建实现自定义的 IOC 容器、依赖注入和获取容器中实例的方法,会使得后期开发过程中代码逻辑更加清晰,各模块之间实现轻耦合的同时交互又异常简单方便。本文将通过使用 Microsoft.Extensions.DependencyInjection 类库,为搭建IOC 容器的各种功能提供一种思路。1 具体实现步骤(1)新建一个 WPF 应用程序(基于.Net Framework 或.Net Core 都可以),并在项目目录下新建 Models、Views、ViewModels 三个目录,用于契合 MVVM 的设计理念。其中 Models 主要放置真实状态内容具象化的模型类以及代表内容的数据层(以现实内容和数据库为基础的建模),Views 视图层处理用户界面,包括各类图形控件、布局和外观以及界面需要用到的资源字典,ViewModels 视图模型作为视图与数据的交互节点与Views 中的视图一一对应,它通过暴露公开的属性和命令将视图抽象化,通过视图各控件属性的绑定,实现视图与数据的交互。(2)在 Views 中新建一个窗口 MainWindow.xaml作为主窗口,并修改 app.xaml 中 StartupUri(项目的启动窗口)为 Views/MainWindow.xaml。处理完成后项目目录下的文件结构如图 1。(3)项目引入需要的三方依赖包。可以通过 NuGet管理器安装 Microsoft.Extensions.DependencyInjection 依赖。这个类库中提供的 ServiceCollection 属性,这个属性的类型中可提供依赖注入的方法。后续会根据此包的功能封装成自定义的 IOC 容器。(4)IOC 容器及其功能实现的封装方法。1.先在ViewModels目录下新建一个MainViewModel类作为 MainWindow 的视图模型,后续以此视图模型为例分析和实现 IOC 容器的单例注入和获取方法。ViewModel 类需要实现 INotifyPropertyChanged 接口,WPF MVVM 框架实现 IOC 依赖注入的一种方法颜杰宋以鹰冯朝晖(比亚迪精密制造有限公司 广东省深圳市 518116)摘要:本文主要介绍如何在 WPF 应用程序中搭建一个使用方便的 IOC 容器,以及如何将对象注入容器和从容器中获取对象的单例。IOC,即控制反转,主要作用是将创建对象的权力转移,一般是交由项目的框架处理。目的是为了实现依赖注入(Dependency Injection,简称 DI)和依赖查找(Dependency Lookup)。主要好处体现在整个项目的对象都交由 IOC 容器管理,单例模式使得各模块之间的数据交换变得非常简单,同时消除前后端、模块间的紧耦合(依赖关系),对协同开发带来极大便捷。关键词:C#;WPF;IOC;MVVM;控制反转;依赖注入;单例模式图 1:项目初始化后的目录数据库系统设计Database System Design电子技术与软件工程Electronic Technology&Software Engineering187可使得其公开属性可完成更新后发出通知的功能,这是MVVM 模式中视图与视图模型双向绑定并实时保持数据双向同步更新的核心,以此实现数据驱动界面。此例中 MainViewModel 继承 ObservableObject 类(此类已实现 INotifyPropertyChanged 接口)。2.设计 IOC 容器。在视图模型 ViewModels 目录下创建名为 ViewModelLocator 的类(借鉴 Mvvmlight 框架中 IOC 容器的类名,方便熟悉此框架者使用),作为实现 IOC 容器对应的具体类。并在容器中提供单例注入以及获取的接口,具体实现参照图 3 中代码。3.图3中第2行,引用Microsoft.Extensions.Dependency Injection 命名空间,此命名空间中的 Service Collection类相当于一个单例工厂,可以很方便的实现全局向其中注入单例对象及获取已注入的对象实例。图 2:NuGet 管理器依赖库安装图 3:IOC 容器的实现数据库系统设计Database System Design电子技术与软件工程Electronic Technology&Software Engineering1884.定 义 类 型 为 IServiceProvider 的 属 性 Services,IServiceProvider 接口提供了 GetService 方法,此方法为泛型方法,可以根据参数类型从容器中方便的获取该类型对应的实例对象;5.设计容器 Services 的初始化方法 InitIoc,此方法中包含单例注入的方式,如图 3 中第 26 行所示,将MainViewModel 以 单 例 的 方 法(AddSingleton)注 入到容器中,后续项目开发过程中有需要注入的对象都可以在此处进行依赖注入。已注入容器的类型,在整个项目中对此类的操作读取可实现针对的是同一个该类型对象,实现全局数据同步与共享。图 3 第 29 行返回 IServiceProvider 接口。在 ViewModelLocator 的构造函数中调用 InitIoc 方法,并将返回的容器赋值给属性Services。6.上述内容已实现如何向IOC容器中注入单例对象,为了简化从容器中取得对象的操作,针对每个注入的单例创建一个对应的用于获取它的公开属性。此属性的get 方法返回从 IOC 容器中获取并返回的对应类型单例对象。如图 3 第 35-41 行内容所示,给 MainViewModel单例创建名为 Main 的公开属性,这样只需要访问 Main属性即可获取 MainViewModel 的单例对象,这种方式即方便后期后端任意位置对其的访问,又非常契合前端的绑定机制实现。(5)此时 IOC 容器的类已创建完成,在整个项目哪一层结构中构建这个容器实例值得思考。如果放在后端代码中构建,会使得前端 xaml 文件中进行数据绑定的操作变得繁琐。将 IOC 容器以资源的方式加载到整个项目的视图层,方便视图层通过数据上下文的绑定实现数据驱动页面,同时在后端通过 FindResource 方法获取前端的资源也是很方便的,所以在此处我们选择在前端构建这个IOC容器。在App.xaml中添加资源方法如图4:1.引用 ViewModelLocator 容器类的命名空间到 APP前端的分部类,别名 vm,xmlns:vm=”clr-namespace:IocDemo.ViewModels”。2.在 Application.Resources 的资源字典中引入 IOC容器 ViewModelLocator,并标注为数据资源 d:IsData Source=”True”。3.将 IOC 容器资源 Key 值定义为”Locator”,方便各个层级模块获取调用,可通过 Key 值很轻松的查找到这个容器资源。4.App.xaml 为整个项目的顶级视图,此处以静态资源的方式引入 IOC 容器后,后续整个项目都可共享这个图 4:视图层 app.xaml 加载 IOC 容器图 5:MainViewModel 定义公开属性图 6:MainWindow 绑定后端数据图 7:定义获取 IOC 容器的全局静态方法数据库系统设计Database System Design电子技术与软件工程Electronic Technology&Software Engineering189资源。所有模块操作的数据都将是 IOC 容器中的单例对象,方便数据生命周期的维持,而不会因为页面卸载导致内存的回收被释放,实现后端数据全局互通有无。(6)Views 视图层以静态资源绑定的方式获取 IOC容器中单例对象并作为数据上下文。1.以主视图 MainWindow 为例,设置视图数据上下文 DataContext 为 MainViewModel 视图模型,并从 IOC容器中获取该类型单例对象进行绑定;DataContext=Binding Source=StaticResource Locator,Path=Main以 Key 值 Locator 获取 IOC 容器的静态资源,并通过路径 Path 指向 MainViewModel 的公开属 Main 完成数据上下文的绑定。2.此时视图 MainWindow 中的控件内容即可绑定视图模型 MainViewModel(已实现 INotifyPropertyChanged接口)的公开属性,实现视图模型数据与视图层控件内容的双向实时更新。例如在 MainViewModel 中定义一个公开属性“TestValue”,set 方法实现更新通知功能。用视图层 MainWindow 中一个 TextBlock 控件的 Text 属性去绑定“TestValue”。如图 5 和图 6 所示。(7)后端全局获取 IOC 容器中实例的方法。因为 IOC 容器已作为全局静态资源构建加载到App.xaml 中,所以后端可以通过定义一个全局可调用的静态方法去获取这个资源。当前项目 Application 中的FindResource 方法通过检索资源 Key 值去实现,返回的资源拆箱处理后即为 IOC 容器 ViewModelLocator 类型的对象实例。(8)后端可以在项目的任意位置调用图 7 中 GetIoc方法获取 IOC 容器,并通过访问容器中的公开属性得到对应的单例对象。例如下面代码通过公开属性 Main 即可获取 MainViewModel 的单例对象。类似的方法,只要在容器初始化时已注入的单例对象都可以轻松的全局进行访问及修改其中的数据,使整个项目各模块之间都可通过 IOC 容器这个中间枢纽完成数据交互,无需额外自定义一些事件或消息处理这些任务,让代码逻辑更加清晰明了。(9)通过参照上述步骤实现的例子,后续在项目的开发过程中,在创建每个视图对应的视图模型后,都可以以单例的形式注入到 IOC 容器中,解耦后端业务逻辑与视图的依赖关系,有利于团队的协作开发,同时这样也会使得视图模型 ViewModel 不会因为视图 View 的关闭或卸载导致被内存释放,造成数据的丢失,无法复原页面内容。每次页面的重新加载都会通过其绑定的数据上下文 Datacontext 从 IOC 容器中获取到相同的一个实例对象,保证数据的共享、留存及重复利用。2 注意的问题因为 IOC 容器从程序开始运行即被构建加载到内存中,生命周期直到整个程序运行结束或者关闭,程序运行的整个过程都不会被释放,持续占用内存空间,为了优化内存的使用率,所以一般只需要往 IOC 容器中注入视图模型层(ViewModel)的内容,此层为程序前后端及各模块数据的交互枢纽,注入视图模型层的单例对象足以满足项目的使用。MVVM 概念框架的设计框图如图 8 所示。参考文献1 刘铁猛.深入浅出WPFM.水利水电出版社,2010.作者简介颜杰(1984-),男,四川省邻水县人。大学本科学历,