如您所知,依赖注入是“控制反转”(IoC) 编程原理的一种形式。这意味着类不会创建它们所依赖的对象,DI 框架具有负责揭示和解决依赖关系的容器。
DevExpress通用订阅官方最新版本免费下载试用、历史版本下载、在线文档和帮助文件下载-灰都网
依赖注入可以解决哪些问题?
假设您有一个使用数据服务获取数据的视图模型:
公共类UserViewModel{MyDataService dataService; public UserViewModel() {this.dataService=new MyDataService();}} 视图模型依赖于服务—— 这意味着MyDataService 是UserViewModel 的依赖项。直接在视图模型类中创建服务非常容易,但这种方法有几个缺点:
这些类紧密链接,每次使用UserViewModel 时,它都会隐式创建MyDataService 的实例。如果以后修改MyDataService的初始化方法,则必须修改MyDataService初始化的所有视图模型。您无法专门为UserViewModel 类创建单元测试,因为它依赖于MyDataService。如果测试失败,您可能无法确定错误是在UserViewModel 还是MyDataService 中。如果将MyDataService 传递给UserViewModel 的构造函数,则可以避免这些问题:
公共类UserViewModel{MyDataService dataService; public UserViewModel(MyDataService dataService) {this.dataService=dataService;}} 不幸的是,这种技术也有缺陷:
在每个类中创建不同的视图模型,并且它们都必须知道如何创建MyDataService。如果不创建静态属性,则很难在多个视图模型之间共享相同的MyDataService 实例。依赖注入的主要思想是集中解决所有依赖关系,这意味着在程序中有一个单独的块来初始化新的类实例并向它们传递参数。虽然您可以为此实现自己的逻辑,但使用DI 框架来帮助避免/消除示例代码会更方便。
依赖注入模式具有以下优点:
这些类是松散耦合的,因此您可以轻松修改依赖项,例如,将MyDataService 替换为MyDataServiceEx。创建单元测试很容易,因为您可以将模拟参数传递给被测类。您的项目结构良好,因为您始终知道所有依赖项的管理位置。
将依赖注入应用到WPF应用程序
.NET 社区有许多出色的框架可以帮助您在应用程序中实现依赖项注入模式,所有这些框架都有两个主要功能:
您可以在容器中注册类。您可以创建具有初始化依赖项的对象。容器是DI 框架中的中心对象,可自动检测和解决类依赖关系。有些框架可以将参数注入到类属性中,但最常见的方法是将参数注入到构造函数中。
让我们修改MainViewModel 构造函数,使其接受接口替换类:
公共类MainViewModel{IDataService dataService; public MainViewModel(IDataService dataService) {this.dataService=dataService;}} 这将允许您将来使用不同的IDataService 实现。
进行此更改后,我们需要创建一个DI 容器来注册MyDataService 并实例化MainViewModel:
protected override void OnStartup(StartupEventArgs e) {base.OnStartup(e);var builder=new ContainerBuilder();//允许Autofac 容器解析未知类型builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());//将MyDataService 类注册为DI容器中的IDataService接口builder.RegisterTypeMyDataService().AsIDataService().SingleInstance();IContainer container=builder.Build();//获取一个MainViewModel实例MainViewModel mainViewModel=container.ResolveMainViewModel();} 本例中我们使用Autofac框架,但您可以使用任何其他DI 框架,例如Unity 或Ninject。 DI 容器创建MainViewModel 并自动将MyDataService 注入到MainViewModel 构造函数中,这样您就可以避免每次创建具有IDataService 参数类型的类时初始化MyDataService。
然后我们需要将MainViewModel 连接到它的视图:MainView,最明显的策略是在视图构造函数中设置DataContext:
public MainView() {InitializeComponent();this.DataContext=container.ResolveMainViewModel();} 但是,要访问DI 容器,您必须将其设置为静态或将其传递给每个视图构造函数。更好的解决方案是创建一个标记扩展,根据其类型返回视图模型实例:
公共类DISource : MarkupExtension{公共静态FuncType,对象解析器{ get;放; }公共类型类型{ get;放; }public override object ProvideValue(IServiceProvider serviceProvider)=Resolver?Invoke(Type);}UserControl DataContext='{ local:DISource Type=local:MainViewModel}' 最初,标记扩展未绑定到任何DI 容器。要允许扩展使用您的容器,请指定视图模型解析器,如下所示:
公共部分类App : Application{protected override void OnStartup(StartupEventArgs e) {base.OnStartup(e);//.IContainer container=builder.Build();DISource.Resolver=(type)={return container.Resolve (type);};}} 这种技术允许DISource 与任何可能的容器一起工作。
依赖注入和DevExpress服务
在上面的示例中,我们使用了不与可视控件通信的抽象数据服务。如您所知,许多DevExpress WPF 服务都使用视图控件,因此服务必须知道要使用哪个控件。例如,如果要将NavigationFrameService 注入到视图模型中,还需要将此服务附加到相应的NavigationFrame 控件。
在包含服务的视图模型中创建一个公共属性并将服务绑定到NavigationFrame:
公共类MainViewModel {公共INavigationService 导航服务{ 获取; }public MainViewModel(INavigationService navigationService)=NavigationService=navigationService;}dxwui:NavigationFramedxmvvm:Interaction.Behaviorscommon:AttachServiceBehavior Service='{绑定NavigationService}'//dxmvvm:Interaction.Behavior s/dxwui:NavigationFrameAttachServiceBehavior 是一个简单的附件操作,即NavigationFrameService.Attach,当服务属性发生变化时被调用。尽管AttachServiceBehavior 未包含在我们的库中,但您可以在此处获取其代码:如何通过依赖注入/AttachServiceBehavior 使用我们的服务。尽管MainViewModel 使用NavigationFrameService,但它不必实现ISupportServices 接口。此外,导航中涉及的所有子视图都可以使用此服务,而无需附加到NavigationFrame ——,因为它已经在主视图级别进行了配置。
并非所有DevExpress 服务都需要可视组件,某些服务(例如DXMessageBoxService 或DXOpenFileDialogService)不需要显式附加,因此您可以像任何其他非DevExpress 服务一样注入它们。
在某些情况下,如果需要为特定视图配置服务,则使用DI 容器来注入服务可能并不明智。情况就是这样,例如,如果您有一个服务绑定到视图模型命令,那么直接在视图中定义该服务并在那里配置所有绑定会容易得多。
用户评论
依赖注入听起来挺高级的,这篇博文能详细解释一下在WPF MVVM中的应用吗?我最近在做一个项目,正好需要这方面的知识。
有5位网友表示赞同!
完全同意,依赖注入在WPF MVVM中确实很重要。能详细讲讲如何设置吗?我在这方面还是个新手。
有13位网友表示赞同!
WPF MVVM中的依赖注入听起来挺有意思的。我之前听说过,但是不知道如何操作。希望这篇博文能给我一些启示。
有6位网友表示赞同!
这篇文章的标题就让我对依赖注入有了更深的认识。不过,我还是不太明白如何设置,希望作者能详细讲解一下。
有13位网友表示赞同!
依赖注入对于提高应用程序的可维护性真的很有帮助。能否详细介绍一下如何设置依赖注入到WPF MVVM应用程序中呢?
有19位网友表示赞同!
我一直在寻找关于WPF MVVM中依赖注入的资料,这篇博文正好解决了我的问题。谢谢作者的分享!
有6位网友表示赞同!
在WPF MVVM中使用依赖注入,听起来可以减少很多重复代码,提高开发效率。能否详细介绍一下具体的设置方法呢?
有18位网友表示赞同!
我对这篇关于WPF MVVM依赖注入的博文很感兴趣,但是我对如何设置还不太清楚。希望作者能给出一些具体的例子。
有9位网友表示赞同!
依赖注入在WPF MVVM中的应用真是太妙了,可以大大提高代码的解耦程度。作者能否详细介绍一下如何实现呢?
有19位网友表示赞同!
学习了这篇文章,我对WPF MVVM中的依赖注入有了更深的理解。不过,在实际操作中我还是遇到了一些困难,希望有经验的读者能提供一些帮助。
有10位网友表示赞同!
这篇博文对依赖注入的解释非常清晰,但是我觉得设置步骤可以更详细一些。我正在学习如何将依赖注入应用到我的项目中。
有14位网友表示赞同!
依赖注入在WPF MVVM中的应用让我眼前一亮,我之前的项目中就有很多重复代码,现在想尝试一下依赖注入。希望这篇文章能给我一些指导。
有12位网友表示赞同!
这篇文章让我对WPF MVVM中的依赖注入有了新的认识,但是我觉得作者在设置步骤上可以更加详细。我正在尝试按照文章中的方法进行操作。
有11位网友表示赞同!
依赖注入在WPF MVVM中的应用确实可以提高开发效率,但是我觉得作者在解释如何设置时可以更加贴近实际操作。
有5位网友表示赞同!
我已经在项目中尝试了依赖注入,效果确实不错。感谢作者分享这篇关于WPF MVVM依赖注入的博文。
有11位网友表示赞同!
对于依赖注入这个概念,我一直很好奇,这篇文章让我有了更深的了解。不过,我还是希望作者能给出一些实际操作的例子。
有13位网友表示赞同!
依赖注入对于提高WPF MVVM应用程序的可维护性有很大的帮助,这篇文章让我受益匪浅。希望作者能继续分享更多相关内容。
有6位网友表示赞同!
这篇关于WPF MVVM依赖注入的博文写得很好,但是对于一些新手来说可能还是有些难度。希望作者能提供更多易于理解的例子。
有14位网友表示赞同!
我已经按照文章中的方法设置了依赖注入,但是效果并不理想。希望有经验的读者能帮我分析一下问题所在。
有9位网友表示赞同!