Inhoudsopgave

MVVM dependency injection in child ViewModels

Deze opzet maakt het mogelijk dat ViewModels repositories of andere afhankelijkheden ontvangen via constructor-injectie.

Patroon Overzicht

De ViewModel van het child control wordt geleverd als een property in de MainWindowViewModel. In XAML wordt de DataContext van het child control gebonden aan deze property met DataContext="{Binding ChildControlViewModel}". Dit maakt het mogelijk om de child ViewModel via de constructor te injecteren, terwijl de view zelf parameterloos blijft.

Opmerking: hoewel dit voorbeeld Avalonia gebruikt, is hetzelfde patroon toepasbaar op WPF, .NET MAUI, Uno en andere .NET MVVM-frameworks. Het kernidee—afhankelijkheden injecteren in child ViewModels via de parent en de DataContext van de child control binden—is framework-onafhankelijk.

Implementatie Stappen

  1. Registreer de services en ViewModels.

    App.axaml.cs

    public class App : Application
    {
        public static IServiceProvider Services { get; private set; } = default!;
    
        public override void Initialize()
        {
            AvaloniaXamlLoader.Load(this);
        }
    
        public override void OnFrameworkInitializationCompleted()
        {
            ServiceCollection services = new();
            services.AddTransient<IRepository, Repository>();
            services.AddTransient<ChildControlViewModel>();
            services.AddTransient<MainWindowViewModel>();
            Services = services.BuildServiceProvider();        
    
            if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
            {
                desktop.MainWindow = new MainWindow
                {
                    DataContext = Services.GetRequiredService<MainWindowViewModel>(),
                    Topmost = true
                };
            }
    
            base.OnFrameworkInitializationCompleted();
        }
    }
  2. Maak het child viewmodel en implementeer constructor injection

    ChildControlViewModel.cs

    public class ChildControlViewModel(IRepository repository)
    {
        public ObservableCollection<string> Items { get; } = new ObservableCollection<string>(repository.GetItems());
    }
  3. Injecteer het ChildControlViewModel in de MainViewModel

    MainWindowViewModel.cs

    public class MainWindowViewModel(ChildControlViewModel childControlViewModel) : ViewModelBase
    {
        public ChildControlViewModel ChildControlViewModel { get; } = childControlViewModel;        
    }
  4. Verbind het child ViewModel in Xaml.

    MainWindow.xaml

    <Window
        xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"        
        xmlns:vlc="clr-namespace:LibVLCSharp.Avalonia;assembly=LibVLCSharp.Avalonia"
        xmlns:exampleApp="using:ExampleApp"
        xmlns:vm="using:ExampleApp.ViewModels"        
        x:Class="ExampleApp.Views.MainWindow"
        mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
        Icon="/Assets/avalonia-logo.ico"
        Title="Example App">
    
        <Design.DataContext>
            <vm:MainWindowViewModel />
        </Design.DataContext>
    
        <exampleApp:ChildControl
            DataContext="{Binding ChildControlViewModel}"
            Grid.Row="1" />
    
    </Window>
© 2024 Rob van der Velden. Alle rechten voorbehouden.