IT评测·应用市场-qidao123.com

标题: WPF/C#:在WPF中怎样实现依靠注入 [打印本页]

作者: 小秦哥    时间: 2024-7-16 12:09
标题: WPF/C#:在WPF中怎样实现依靠注入
前言

本文通过 WPF Gallery 这个项目学习依靠注入的相关概念与怎样在WPF中进行依靠注入。
什么是依靠注入

依靠注入(Dependency Injection,简称DI)是一种计划模式,用于实现控制反转(Inversion of Control,简称IoC)原则。依靠注入的主要目的是将对象的创建和对象之间的依靠关系的管理从对象内部转移到外部容器或框架中,从而提高代码的可维护性、可测试性和机动性。
依靠注入的核心概念
依靠注入的范例
构造函数注入:依靠的对象通过类的构造函数传递。
  1. public class OrderService
  2. {
  3.     private readonly IProductRepository _productRepository;
  4.     public OrderService(IProductRepository productRepository)
  5.     {
  6.         _productRepository = productRepository;
  7.     }
  8. }
复制代码
属性注入:依靠的对象通过类的公共属性传递。
  1. public class OrderService
  2. {
  3.     public IProductRepository ProductRepository { get; set; }
  4. }
复制代码
方法注入:依靠的对象通过类的方法参数传递。
  1. public class OrderService
  2. {
  3.     public void ProcessOrder(IProductRepository productRepository)
  4.     {
  5.         // 使用 productRepository 处理订单
  6.     }
  7. }
复制代码
为什么要进行依靠注入

依靠注入(Dependency Injection,简称DI)是一种计划模式,通过它可以将对象的创建和对象之间的依靠关系的管理从对象内部转移到外部容器或框架中。进行依靠注入有以下几个紧张的原因和长处:
怎样实现依靠注入

本文通过 WPF Gallery 项目学习在WPF中怎样使用依靠注入,代码地址:
https://github.com/microsoft/WPF-Samples/blob/main/SampleApplications/WPFGallery
这个项目中实现依靠注入,使用到了这两个包:

首先查看App.xaml.cs中的内容:
  1. public partial class App : Application
  2. {
  3.     private static readonly IHost _host = Host.CreateDefaultBuilder()
  4.         .ConfigureServices((context, services) =>
  5.         {
  6.             services.AddSingleton<INavigationService, NavigationService>();
  7.             services.AddSingleton<MainWindow>();
  8.             services.AddSingleton<MainWindowViewModel>();
  9.             
  10.             services.AddTransient<DashboardPage>();
  11.             services.AddTransient<DashboardPageViewModel>();
  12.             services.AddTransient<ButtonPage>();
  13.             services.AddTransient<ButtonPageViewModel>();
  14.             services.AddTransient<CheckBoxPage>();
  15.             services.AddTransient<CheckBoxPageViewModel>();
  16.             services.AddTransient<ComboBoxPage>();
  17.             services.AddTransient<ComboBoxPageViewModel>();
  18.             services.AddTransient<RadioButtonPage>();
  19.             services.AddTransient<RadioButtonPageViewModel>();
  20.             services.AddTransient<SliderPage>();
  21.             services.AddTransient<SliderPageViewModel>();
  22.             services.AddTransient<CalendarPage>();
  23.             services.AddTransient<CalendarPageViewModel>();
  24.             services.AddTransient<DatePickerPage>();
  25.             services.AddTransient<DatePickerPageViewModel>();
  26.             services.AddTransient<TabControlPage>();
  27.             services.AddTransient<TabControlPageViewModel>();
  28.             services.AddTransient<ProgressBarPage>();
  29.             services.AddTransient<ProgressBarPageViewModel>();
  30.             services.AddTransient<MenuPage>();
  31.             services.AddTransient<MenuPageViewModel>();
  32.             services.AddTransient<ToolTipPage>();
  33.             services.AddTransient<ToolTipPageViewModel>();
  34.             services.AddTransient<CanvasPage>();
  35.             services.AddTransient<CanvasPageViewModel>();
  36.             services.AddTransient<ExpanderPage>();
  37.             services.AddTransient<ExpanderPageViewModel>();
  38.             services.AddTransient<ImagePage>();
  39.             services.AddTransient<ImagePageViewModel>();
  40.             services.AddTransient<DataGridPage>();
  41.             services.AddTransient<DataGridPageViewModel>();
  42.             services.AddTransient<ListBoxPage>();
  43.             services.AddTransient<ListBoxPageViewModel>();
  44.             services.AddTransient<ListViewPage>();
  45.             services.AddTransient<ListViewPageViewModel>();
  46.             services.AddTransient<TreeViewPage>();
  47.             services.AddTransient<TreeViewPageViewModel>();
  48.             services.AddTransient<LabelPage>();
  49.             services.AddTransient<LabelPageViewModel>();
  50.             services.AddTransient<TextBoxPage>();
  51.             services.AddTransient<TextBoxPageViewModel>();
  52.             services.AddTransient<TextBlockPage>();
  53.             services.AddTransient<TextBlockPageViewModel>();
  54.             services.AddTransient<RichTextEditPage>();
  55.             services.AddTransient<RichTextEditPageViewModel>();
  56.             services.AddTransient<PasswordBoxPage>();
  57.             services.AddTransient<PasswordBoxPageViewModel>();
  58.             services.AddTransient<ColorsPage>();
  59.             services.AddTransient<ColorsPageViewModel>();
  60.             services.AddTransient<LayoutPage>();
  61.             services.AddTransient<LayoutPageViewModel>();
  62.             services.AddTransient<AllSamplesPage>();
  63.             services.AddTransient<AllSamplesPageViewModel>();
  64.             services.AddTransient<BasicInputPage>();
  65.             services.AddTransient<BasicInputPageViewModel>();
  66.             services.AddTransient<CollectionsPage>();
  67.             services.AddTransient<CollectionsPageViewModel>();
  68.             services.AddTransient<MediaPage>();
  69.             services.AddTransient<MediaPageViewModel>();
  70.             services.AddTransient<NavigationPage>();
  71.             services.AddTransient<NavigationPageViewModel>();
  72.             services.AddTransient<TextPage>();
  73.             services.AddTransient<TextPageViewModel>();
  74.             services.AddTransient<DateAndTimePage>();
  75.             services.AddTransient<DateAndTimePageViewModel>();
  76.             services.AddTransient<StatusAndInfoPage>();
  77.             services.AddTransient<StatusAndInfoPageViewModel>();
  78.             services.AddTransient<SamplesPage>();
  79.             services.AddTransient<SamplesPageViewModel>();
  80.             services.AddTransient<DesignGuidancePage>();
  81.             services.AddTransient<DesignGuidancePageViewModel>();
  82.             services.AddTransient<UserDashboardPage>();
  83.             services.AddTransient<UserDashboardPageViewModel>();
  84.             services.AddTransient<TypographyPage>();
  85.             services.AddTransient<TypographyPageViewModel>();
  86.             services.AddSingleton<IconsPage>();
  87.             services.AddSingleton<IconsPageViewModel>();
  88.             services.AddSingleton<SettingsPage>();
  89.             services.AddSingleton<SettingsPageViewModel>();
  90.             services.AddSingleton<AboutPage>();
  91.             services.AddSingleton<AboutPageViewModel>();
  92.         }).Build();
  93.     [STAThread]
  94.     public static void Main()
  95.     {
  96.         _host.Start();
  97.         App app = new();
  98.         app.InitializeComponent();
  99.         app.MainWindow = _host.Services.GetRequiredService<MainWindow>();
  100.         app.MainWindow.Visibility = Visibility.Visible;
  101.         app.Run();
  102.     }
  103. }
复制代码

IHost是什么?
在C#中,IHost 是一个接口,它是.NET 中用于构建和配置应用程序的Host的概念的抽象。IHost接口界说了启动、运行和管理应用程序所需的服务和组件的集合。它通常用于ASP.NET Core应用程序,但也适用于其他范例的.NET 应用程序,如控制台应用程序或WPF程序。

IHost接口由HostBuilder类实现,它提供了创建和配置IHost实例的方法。HostBuilder允许你添加各种服务,如日志记载、配置、依靠注入容器等,并配置应用程序的启动和停止活动。


提供了用于使用预配置默认值创建Microsoft.Extensions.Hosting.IHostBuilder实例的方便方法。

返回一个IHostBuilder。


向容器中添加服务。此操纵可以调用多次,其效果是累加的。
参数configureDelegate的含义是配置Microsoft.Extensions.DependencyInjection.IServiceCollection的委托,
该集合将用于构造System.IServiceProvider。
该委托必要两个参数范例分别为HostBuilderContext、IServiceCollection没有返回值。

这里传入了一个满足该委托范例的Lambda表达式。
在C#中,() => {}是一种Lambda表达式的语法。Lambda表达式是一种轻量级的委托包装器,它可以让你界说一个匿名方法,并将其作为参数传递给支持委托或表达式树的方法。
Lambda表达式提供了一种简洁的方式来界说方法,特别是在必要将方法作为参数传递给其他方法时,它们非常有用。

在添加服务,这里出现了两种生命周期,除了AddSingleton、AddTransient外尚有AddScoped。
这些方法界说了服务的生命周期,即服务实例在应用程序中的创建和管理方式。
AddSingleton

AddTransient

AddScoped

使用这些服务
在Main函数中:

启动_host,通过_host.Services.GetRequiredService<MainWindow>();获取MainWindow实例。
以MainWindow类为例,查看MainWindow.xaml.cs中MainWindow的构造函数:
  1. public MainWindow(MainWindowViewModel viewModel, IServiceProvider serviceProvider, INavigationService navigationService)
  2. {
  3.     _serviceProvider = serviceProvider;
  4.     ViewModel = viewModel;
  5.     DataContext = this;
  6.     InitializeComponent();
  7.     Toggle_TitleButtonVisibility();
  8.     _navigationService = navigationService;
  9.     _navigationService.Navigating += OnNavigating;
  10.     _navigationService.SetFrame(this.RootContentFrame);
  11.     _navigationService.Navigate(typeof(DashboardPage));
  12.     WindowChrome.SetWindowChrome(
  13.         this,
  14.         new WindowChrome
  15.         {
  16.             CaptionHeight = 50,
  17.             CornerRadius = default,
  18.             GlassFrameThickness = new Thickness(-1),
  19.             ResizeBorderThickness = ResizeMode == ResizeMode.NoResize ? default : new Thickness(4),
  20.             UseAeroCaptionButtons = true
  21.         }
  22.     );
  23.     this.StateChanged += MainWindow_StateChanged;
  24. }
复制代码
去掉与本主题无关的内容之后,如下所示:
  1. public MainWindow(MainWindowViewModel viewModel, IServiceProvider serviceProvider, INavigationService navigationService)
  2. {
  3.     _serviceProvider = serviceProvider;
  4.     ViewModel = viewModel;
  5.     _navigationService = navigationService;  
  6. }
复制代码
有没有发现不用自己new这些对象了,这些对象的创建由依靠注入容器来管理,在必要这些对象的时候,像如今这样通过构造函数中注入即可。
如果没有用依靠注入,可能就是这样子的:
  1. public MainWindow()
  2. {
  3.     _serviceProvider = new IServiceProvider();
  4.     ViewModel = new MainWindowViewModel();
  5.     _navigationService = new INavigationService();  
  6. }
复制代码
总结

本文先介绍依靠注入的概念,再表明为什么要进行依靠注入,最后通过 WPF Gallery 这个项目学习怎样在WPF中使用依靠注入。
参考

1、[WPF-Samples/Sample Applications/WPFGallery at main · microsoft/WPF-Samples (github.com)](https://github.com/microsoft/WPF-Samples/tree/main/Sample Applications/WPFGallery)

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4