Avalonia中实现依赖注入及多视图与视图模型注册方法
在Avalonia中实现类似MAUI的多视图多ViewModel依赖注入(搭配MVVM Community Toolkit)
你当前代码的核心问题是创建了两个独立的ServiceCollection和ServiceProvider,导致依赖无法共享,且未正确让Avalonia框架使用你的DI容器解析视图,因此构造函数注入不生效。以下是适配Avalonia的正确实现方案:
步骤1:统一注册所有服务、ViewModel与视图
不要拆分多个ServiceCollection,将所有依赖注册到同一个集合中,同时注册视图(Avalonia需要通过DI容器解析视图才能自动注入构造函数依赖)。
修改你的ServiceCollectionExtensions:
using incomeExpensTrckAVALONIA.ViewModels; using incomeExpensTrckAVALONIA.Views; using Microsoft.Extensions.DependencyInjection; namespace incomeExpensTrckAVALONIA { public static class ServiceCollectionExtensions { public static void AddAppServices(this IServiceCollection collection) { // 注册ViewModel,根据业务需求选择生命周期(Transient/Singleton/Scoped) collection.AddTransient<MainViewModel>(); collection.AddSingleton<ExpensePageViewModel>(); // 注册视图,让Avalonia通过DI解析视图并自动注入依赖 collection.AddTransient<MainWindow>(); collection.AddTransient<ExpensePageView>(); // 在此添加其他业务服务,例如数据访问、API服务等 // collection.AddSingleton<IMyDataService, MyDataService>(); } } }
步骤2:配置Avalonia关联DI容器
在App类中创建单个ServiceCollection,注册所有服务后构建ServiceProvider,并关联到Avalonia的Locator,让框架自动使用DI解析视图与依赖。
修改App类:
using Avalonia; using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Data.Core.Plugins; using Avalonia.Markup.Xaml; using incomeExpensTrckAVALONIA.Views; using Microsoft.Extensions.DependencyInjection; using Avalonia.Controls; namespace incomeExpensTrckAVALONIA; public partial class App : Application { public override void Initialize() { AvaloniaXamlLoader.Load(this); } public override void OnFrameworkInitializationCompleted() { // 移除Avalonia自带数据验证,避免与MVVM Community Toolkit重复 BindingPlugins.DataValidators.RemoveAt(0); // 注册所有应用服务 var services = new ServiceCollection(); services.AddAppServices(); // 构建ServiceProvider var serviceProvider = services.BuildServiceProvider(); // 将ServiceProvider绑定到Avalonia Locator,让框架使用DI解析视图 Locator.CurrentMutable.BindToServiceProvider(serviceProvider); if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { // 通过ServiceProvider解析MainWindow,自动注入ViewModel到构造函数 desktop.MainWindow = serviceProvider.GetRequiredService<MainWindow>(); // 若需在MainWindow中导航到ExpensePageView,同样通过DI解析: // var expenseView = serviceProvider.GetRequiredService<ExpensePageView>(); // desktop.MainWindow.Content = expenseView; } else if (ApplicationLifetime is ISingleViewApplicationLifetime singleViewPlatform) { // 单视图场景下通过DI解析视图 singleViewPlatform.MainView = serviceProvider.GetRequiredService<ExpensePageView>(); } base.OnFrameworkInitializationCompleted(); } }
步骤3:视图的构造函数注入(与MAUI一致)
视图代码可以和MAUI保持几乎一致,直接在构造函数中接收ViewModel并设置为DataContext:
using incomeExpensTrckAVALONIA.ViewModels; using Avalonia.Controls; namespace incomeExpensTrckAVALONIA.Views; public partial class ExpensePageView : UserControl { public ExpensePageView(ExpensePageViewModel expensePageViewModel) { InitializeComponent(); DataContext = expensePageViewModel; } }
MainWindow的实现类似:
using incomeExpensTrckAVALONIA.ViewModels; using Avalonia.Controls; namespace incomeExpensTrckAVALONIA.Views; public partial class MainWindow : Window { public MainWindow(MainViewModel mainViewModel) { InitializeComponent(); DataContext = mainViewModel; } }
关键注意点
- 所有依赖必须注册到同一个
ServiceCollection,确保依赖关系可共享。 - 必须将
ServiceProvider绑定到Avalonia的Locator,否则框架无法自动使用DI解析视图。 - 视图必须通过
serviceProvider.GetRequiredService<T>()获取,而非手动new,才能触发构造函数注入。
内容的提问来源于stack exchange,提问作者BaselE
相关产品推荐
相关产品推荐

