WPF随笔—依赖注入依赖注入WPF中依赖注入示例1手动绑定View-ViewModel示例2自动依赖注入依赖注入从工厂模式到依赖注入他们都减轻了类创建时的耦合程度依赖注入尤为甚之。WPF中依赖注入聚焦于WPF本身WPF项目通常实现MVVM模式他将视图逻辑和业务逻辑解耦实现了客户端程序上的前后端分离。依赖注入基于了一种无感的方式将View和ViewModel联系起来。对于业务逻辑层或者数据处理层中的各种服务依赖注入不仅减少了耦合性他的单例注入还提供了较好的线程安全性。示例1手动绑定View-ViewModeltips: View和ViewModel建立关联的关键点在于View的DataContext是ViewModelIOC容器选型IServiceProviderapp.xaml.cspublicpartialclassApp:Application{publicstaticnewAppCurrent(App)Application.Current;publicIServiceProvider_Services{get;set;}privatestaticIServiceProviderConfigureServices(){IServiceCollectionServiceCollctionsnewServiceCollection();//viewmodelsServiceCollctions.AddSingletonMainViewModel();//viewsServiceCollctions.AddSingleton(spnewMainView(){DataContextsp.GetServiceMainViewModel(),});//returnvarproviderServiceCollctions.BuildServiceProvider();returnprovider;}示例2自动依赖注入设计要点利用反射attribute。扫描程序集中包含特定特征的类型利用反射的方式注入容器中。自动依赖注入attributeattribute中声明了注入的分类、生命周期。当分类为Default时不进行注册publicenumServiceCategory{Default,// 默认类别不进行注册View,ViewModel,Service,Repository}/// summary/// 用于标记需要自动注入的类(View有且仅有无参构造)/// /summary[AttributeUsage(AttributeTargets.Class,AllowMultiplefalse,Inheritedfalse)]publicsealedclassAutoInjectAttribute:Attribute{/// summary/// 可以用来区分不同的注入类别例如View、ViewModel、Service、Repository/// /summarypublicServiceCategoryCategory{get;}/// summary/// 生命周期默认为Transient/// /summarypublicServiceLifetimeLifeTime{get;}publicAutoInjectAttribute(ServiceCategorycategoryServiceCategory.Default,ServiceLifetimelifeTimeServiceLifetime.Transient){Categorycategory;LifeTimelifeTime;}}自动依赖注入扩展配合attribute 利用反射进行依赖注入view会根据命名规则自动将datacontext注入为对应的viewmodel当然也可以通过ViewModelMap进行指定。publicstaticclassViewModelMap{publicstaticDictionaryType,TypeMap{get;}[];}publicstaticclassServiceProviderExtension{/// summary/// 自动DI注入/// /summary/// param nameservices/param/// param nameassemblies/parampublicstaticvoidAutoInject(thisIServiceCollectionservices,paramsAssembly[]assemblies){// 获取程序集中的所有类型筛选出标有AutoInjectAttribute特性的类vartypesassemblies.SelectMany(aa.GetTypes()).Where(t!t.IsAbstract!t.IsInterface).Where(tt.GetCustomAttributeAutoInjectAttribute()!null).ToList();// viewodelsvarviewModelstypes.Where(tt.GetCustomAttributeAutoInjectAttribute()!.CategoryServiceCategory.ViewModel);// viewsvarviewstypes.Where(tt.GetCustomAttributeAutoInjectAttribute()!.CategoryServiceCategory.View);//othervarotherstypes.Where(tt.GetCustomAttributeAutoInjectAttribute()!.CategoryServiceCategory.Service||t.GetCustomAttributeAutoInjectAttribute()!.CategoryServiceCategory.Repository);// 1. 先注册所有 ViewModel普通规则foreach(varvmTypeinviewModels)RegisterByLifetime(services,vmType);// 2. 注册其他foreach(vartypeinothers)RegisterByLifetime(services,type);// 3. 最后注册 Viewforeach(varviewTypeinviews){varvmTypeFindMatchingViewModel(viewType,viewModels.ToList());if(vmType!null){//根据命名规则注入viewmodelRegisterByLifetime(services,viewType,spsp.GetService(vmType)!);}else{//根据表(自定义规则)注入viewmodelvmTypeViewModelMap.Map.FirstOrDefault(kvpkvp.KeyviewType).Value;if(vmType!nullviewModels.Contains(vmType)){RegisterByLifetime(services,viewType,spsp.GetService(vmType)!);}else{//啥都没有找到直接注册RegisterByLifetime(services,viewType);}}}}/// summary/// 根据声明周期注册/// /summary/// param nameservices/param/// param nametype/paramprivatestaticvoidRegisterByLifetime(IServiceCollectionservices,Typetype,FuncIServiceProvider,object?spfunnull){varattrtype.GetCustomAttributeAutoInjectAttribute()!;if(spfunnull)switch(attr.LifeTime){caseServiceLifetime.Singleton:services.AddSingleton(type);break;caseServiceLifetime.Scoped:services.AddScoped(type);break;caseServiceLifetime.Transient:services.AddTransient(type);break;}elseswitch(attr.LifeTime){caseServiceLifetime.Singleton:services.AddSingleton(type,sp{varview(FrameworkElement)Activator.CreateInstance(type)!;view.DataContextspfun(sp);returnview;});break;caseServiceLifetime.Scoped:services.AddScoped(type,sp{varview(FrameworkElement)Activator.CreateInstance(type)!;view.DataContextspfun(sp);returnview;});break;caseServiceLifetime.Transient:services.AddTransient(type,sp{varview(FrameworkElement)Activator.CreateInstance(type)!;view.DataContextspfun(sp);returnview;});break;}}privatestaticType?FindMatchingViewModel(TypeviewType,ListTypeviewModels){varviewNameviewType.Name;// 规则1直接加 ViewModel 后缀varcandidatesnewListstring{viewNameViewModel,viewName.Replace(View,)ViewModel,viewName.Replace(Window,)ViewModel,viewName.Replace(Page,)ViewModel,};// 去重后按优先级查找foreach(varcandidateincandidates.Distinct()){varmatchviewModels.FirstOrDefault(vmvm.Namecandidate);if(match!null)returnmatch;}returnnull;}}app.xaml.cspublicpartialclassApp:Application{publicstaticnewAppCurrent(App)Application.Current;publicIServiceProviderServiceProvider{get;privateset;}#regionConstructorpublicApp(){ServiceProviderRegisterComponents();}#endregion#region依赖注入privatestaticAssembly[]ScanMyAssemblies(){varbaseDirAppDomain.CurrentDomain.BaseDirectory;returnDirectory.GetFiles(baseDir,*.dll).Where(f{varnamePath.GetFileNameWithoutExtension(f);// 只加载你自己的项目 DLLreturnname.Contains(FcMonitor)||name.Contains(GeneralWPF);}).Select(f{try{returnAssembly.LoadFrom(f);}catch{returnnull;}}).Where(aa!null).ToArray()!;}privateIServiceProviderRegisterComponents(){varservicesnewServiceCollection();//自动扫描程序集并注册services.AutoInject(ScanMyAssemblies());returnservices.BuildServiceProvider();}#endregion#region启动窗口privatestaticMutex_mutexnewMutex();privatevoidApplication_Startup(objectsender,StartupEventArgse){// 确保单实例运行if(_mutex.WaitOne()false){MessageBox.Show(Another instance is already running.);Application.Current.Shutdown();}varwindowServiceProvider.GetServiceLoginView();window.Show();}#endregion}特征使用方式[AutoInject(ServiceCategory.ViewModel,ServiceLifetime.Transient)]publicpartialclassLoginViewModel:ObservableObject{[ObservableProperty]privatestring_username;[ObservableProperty]privatestring_password;}/// summary/// LoginView.xaml 的交互逻辑/// /summary[AutoInject(ServiceCategory.View,ServiceLifetime.Transient)]publicpartialclassLoginView:Window{publicLoginView(){InitializeComponent();}}运行结果