跳至内容
通过 Host 在 WPF 中进行依赖注入

通过 Host 在 WPF 中进行依赖注入

2026-04-06

运行环境:

  • .NET 10
  • Microsoft.Extensions.Hosting 10.0.5

什么是依赖注入

依赖注入,顾名思义是将对象的依赖交由外部管理,然后在需要的时候添加进来,替代内部实例化,以降低耦合的设计模式。

在 .NET 中使用 Host 来管理对象依赖,同时还包括配置管理和日志记录等功能,在这里主要介绍依赖注入,其他的不过多赘述。

如何在 WPF 中使用依赖注入

在 WPF 中,程序的启动入口是 App.xaml.cs,要想让 Host 贯穿整个 WPF 软件的生命周期,我们需要在这里构建 Host,然后启动。

前置条件

安装必要的 NuGet 包,这是因为 .NET 不自带 Host,需要手动添加。

dotnet add package Microsoft.Extensions.Hosting --version 10.0.5

修改 App.xaml

删除默认启动窗口,交给 Host 管理。

<Application x:Class="WpfApp1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <!-- 删掉默认的 StartupUri="MainWindow.xaml" -->
</Application>

修改 App.xaml.cs

在后置代码中,将需要依赖注入的对象,注册到 Host 中,然后构建并启动 Host。

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Windows;

namespace WpfApp1;

public partial class App : Application
{
    // 全局主机:整个应用唯一的核心对象
    public static IHost AppHost { get; private set; }

    // 应用启动事件
    protected override async void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        // 1. 创建 Host 程序构建器
        var builder = Host.CreateApplicationBuilder();

        // 2. 注册所有窗口、服务
        ConfigureServices(builder.Services);

        // 3. 构建主机
        AppHost = builder.Build();

        // 4. 启动主机(非阻塞模式)
        await AppHost.StartAsync();

        // 5. 从 Host 中获取已注册的对象
        var mw = AppHost.Services.GetRequiredService<MainWindow>();

        // 6. 显示主窗口
        mw.Show();
    }

    // 服务注册:所有需要自动创建的对象写这里
    private void ConfigureServices(IServiceCollection services)
    {
        // 注册主窗口
        services.AddSingleton<MainWindow>();
    }

    // 应用关闭事件
    protected override async void OnExit(ExitEventArgs e)
    {
        await AppHost.StopAsync();
        AppHost.Dispose();
        
        base.OnExit(e);
    }
}

Host 支持三种服务生命周期

关于对象依赖,Host 支持三种服务生命周期:

  • 瞬时 (Transient):每次请求创建新实例
  • 作用域 (Scoped):每个作用域内共享一个实例
  • 单例 (Singleton):整个应用生命周期内共享一个实例

在上面的代码中,正是使用了单例生命周期,在整个 WPF 应用生命周期里,只会创建一个实例。

// 1. 瞬时:每次用都创建新对象
services.AddTransient<MyTool>();

// 2. 作用域:一个作用域内共用一个
services.AddScoped<MainViewModel>();

// 3. 单例:整个应用只创建 1 个对象
services.AddSingleton<MainWindow>();

注册对象依赖时,可以指定接口和具体的实现类,以添加瞬时生命周期为例:

services.AddTransient<IMyTool, MyTool>();

当检测到需要注入 IMyTool 类型的依赖时,就会实例化 MyTool 类型的对象,给需要者。

简单的使用演示

MainWindow 注入 ViewModel,作为数据上下文。

新建 ViewModel

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WpfApp1;

public class MainWindowViewModel : INotifyPropertyChanged
{
    // ... 具体内容省略 ...
}

ConfigureServices() 注册

services.AddSingleton<MainWindow>();
services.AddTransient<MainWindowViewModel>();

MainWindow 构造函数注入

using System.Windows;

namespace WpfApp1;

public partial class MainWindow : Window
{
    public MainWindow(MainWindowViewModel viewModel)
    {
        InitializeComponent();
        DataContext = viewModel;
    }
}
最后更新于