Search code examples
c#wpfdependency-injection.net-6.0

How bind a ViewModel to a view with with dependency injected service in WPF


Background:

I implemented dependency injection in a WPF application using Microsoft.Extensions.DependencyInjection.

App.xaml.cs

protected override async void OnStartup(StartupEventArgs e)
{
    AppHost = Host.CreateDefaultBuilder()
        .ConfigureServices((hostContext, services) =>
        {
            services.AddTransient<IFileRepository, FileRepository>();
            services.AddSingleton<MainWindow>();

        }).Build();

    await AppHost!.StartAsync();
    var startupForm = AppHost.Services.GetRequiredService<MainWindow>();
    startupForm.Show();

    base.OnStartup(e);
}

In my OpenProjectViewModel, I inject the fileRepository.

public IFileRepository fileRepository { get; }
public OpenProjectViewModel(IFileRepository _fileRepository)
{
    fileRepository = _fileRepository;
}

In OpenProjectView.xaml I set the datacontext

<UserControl.DataContext>
    <local:OpenProjectViewModel/>
</UserControl.DataContext>

The problem

When that app starts, it doesn't like that I don't have a parameterless constructor in OpenProjectViewModel. When I add a parameterless constructor in OpenProjectViewModel, the app starts but the fileRepository is then empty because it hasn't been injected.

The question

Is there a way to let the app know when it should inject the FileRepository when the OpenProjectViewModel is being used? I followed this guide to set up the DI. But Tim shows you how to set it up in the view code-behind.

Let me know if I missed sharing anything. Thank you for all the help in advance.


Solution

  • You can't instantiate a viewmodel in XAML unless you're relying on the parameterless constructor.

    You should use

    AppHost.Services.GetRequiredService <MainWindowViewModel>()
    

    And set DataContext of MainWindow in code to the result.

    That will then pass IFileRepository in as a parameter to the constructor.