最近在學WPF,上一篇文章記錄了WPF的MVVM自己實現和用框架的區別(WPF+MVVM入門學習),接下這篇文章記錄一下在WPF中使用IOC,這里演示用的是微軟官方的DependencyInjection,也可以用其他的第三方框架。
項目源碼:https://gitee.com/cplmlm/SelfServiceReportPrinter
GitHub - cplmlm/SelfServiceReportPrinter: WPF+IOC+MVVM 醫院自助檢驗檢查報告打印
推薦學習博主:B站UP十月的寒流
一、基本概念
為什么要用IOC?
可以提高代碼的耦合度、更方便的控制生命周期、提高代碼復用和可維護性、便于測試。
控制反轉
本來要在一個類里面實現依賴,現在我們可以把這個依賴抽出來。
依賴注入
通過依賴的方式注入到類里面的,我們通常使用構造函數注入,還有屬性注入、接口注入。
生命周期
?名稱 | ?概念 | ?使用場景 |
AddSingleton(單例) | 在整個應用程序生命周期中只有一個實例 | 例如配置數據庫連接、身份驗證等服務。 |
AddScoped(作用域) | 該對象的生命周期與請求的作用域一致 | 這種方式適用于需要在請求期間處理共享狀態的服務。例如:請求中可能會使用一個數據庫上下文來處理數據庫相關操作,這時候使用 AddScoped 就可以保證數據庫上下文的實例在請求期間是唯一的,從而避免了多個請求之間的沖突和數據錯亂。 |
AddTransient(瞬時) | 每次服務請求都會創建一個新的實例 | ?適用于需要經常創建和銷毀的輕型服務。例如, 日志記錄服務、輕量級對象、單次使用對象 |
二、示例代碼
1、安裝Microsoft.Extensions.DependencyInjectio包。
2、在app.cs添加以下代碼,目的是為了實現注入,我這里直接從微軟官方復制過來的,代碼地址:?CommunityToolkit.Mvvm 的 IoC 控制反轉
/// <summary>/// Interaction logic for App.xaml/// </summary>public partial class App : Application{public App(){Services = ConfigureServices();this.InitializeComponent();}/// <summary>/// 獲取當前應用程序實例/// </summary>public new static App Current => (App)Application.Current;/// <summary>/// 獲取當前應用程序的服務提供程序/// </summary>public IServiceProvider Services { get; }/// <summary>/// 配置服務/// </summary>private static IServiceProvider ConfigureServices(){ var services = new ServiceCollection();services.AddTransient<KeyPressViewModelCommunityToolkit>();services.AddTransient<KeyPressViewModelPrism>();services.AddTransient<KeyPressViewModel>();services.AddTransient(sp=>new MainWindow() { DataContext=sp.GetRequiredService<KeyPressViewModelCommunityToolkit>()});return services.BuildServiceProvider();}}
3、MainWindow窗口我們也是通過注入的方式,所有和之前的有區別,之前是在StartupUri設置的,通過依賴注入的方式需要重寫了OnStartup方法。
修改前:
<Application x:Class="WpfAppMvvm.App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:WpfAppMvvm"StartupUri="MainWindow.xaml"><Application.Resources></Application.Resources>
</Application>
修改后:
<Application x:Class="SelfServiceReportPrinter.App"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:SelfServiceReportPrinter"><Application.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/SkinDefault.xaml"/><ResourceDictionary Source="pack://application:,,,/HandyControl;component/Themes/Theme.xaml"/><ResourceDictionary Source="/Resources/CommonDictionary.xaml"/></ResourceDictionary.MergedDictionaries></ResourceDictionary></Application.Resources>
</Application>
public partial class App : Application
{public App(){Services = ConfigureServices();this.InitializeComponent();}/// <summary>/// 獲取當前應用程序實例/// </summary>public new static App Current => (App)Application.Current;/// <summary>/// 獲取當前應用程序的服務提供程序/// </summary>public IServiceProvider Services { get; }/// <summary>/// 配置服務/// </summary>private static IServiceProvider ConfigureServices(){ var services = new ServiceCollection();services.AddTransient<KeyPressViewModelCommunityToolkit>();services.AddTransient<KeyPressViewModelPrism>();services.AddTransient<KeyPressViewModel>();services.AddTransient(sp=>new MainWindow() { DataContext=sp.GetRequiredService<KeyPressViewModelCommunityToolkit>()});return services.BuildServiceProvider();}/// <summary>/// 啟動應用程序/// </summary>/// <param name="e"></param>protected override void OnStartup(StartupEventArgs e){base.OnStartup(e);MainWindow= Services.GetRequiredService<MainWindow>();MainWindow?.Show();}
}