Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dependency Injection in .NET Core 3.0 for WPF

I’m quite familiar with ASP.NET Core and the support for dependency injection out of the box. Controllers can require dependencies by adding a parameter in their constructor. How can dependencies be achieved in WPF UserControls? I tried adding a parameter to the constructor, but that didn’t work. I love the IOC concept and would prefer to bring this forward to WPF.

like image 390
user842818 Avatar asked Feb 26 '19 01:02

user842818


2 Answers

I have recently come across this requirement to my project and I solved it this way.

For Dependency Injection in .NET Core 3.0 for WPF. After you create a WPF Core 3 project in your solution, you need to install/add NuGet packages:

Microsoft.Extensions.DependencyInjection

In my case, I created a class called LogBase that I want to use for logging, so in your App class, add the following (and ya this is just a basic example):

private readonly ServiceProvider _serviceProvider;

public App()
{
    var serviceCollection = new ServiceCollection();
    ConfigureServices(serviceCollection);
    _serviceProvider = serviceCollection.BuildServiceProvider();
}
    
private void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<ILogBase>(new LogBase(new FileInfo($@"C:\temp\log.txt")));
    services.AddSingleton<MainWindow>();
}
    
private void OnStartup(object sender, StartupEventArgs e)
{
    var mainWindow = _serviceProvider.GetService<MainWindow>();
    mainWindow.Show();
}

In your App.xaml, add Startup="OnStartup" so it looks like this:

<Application x:Class="VaultDataStore.Wpf.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:VaultDataStore.Wpf"
             Startup="OnStartup">
    <Application.Resources>
        
    </Application.Resources>
</Application>

So in your MainWindow.xaml.cs, you inject ILogBase in the constructor like this:

private readonly ILogBase _log;

public MainWindow(ILogBase log)
{
    _log = log;

    ...etc.. you can use _log over all in this class

In my LogBase class, I use any logger I like in my way.

I have added all this together in this GitHub repo.


Meanwhile, I have been asked how to use injection inside user control. I come up with this solution if some one get the benefit of it. Check it here.

like image 196
Maytham Avatar answered Oct 17 '22 15:10

Maytham


maytham-ɯɐɥʇʎɐɯ answer to configure Dependency Injection from App class and Startup method is good except I implement IServiceProvider as a property

        public IServiceProvider ServiceProvider { get; private set; }

The next step is "how to inject viewmodels" ?

I don't like the viewmodel injection in the window constructor (in code behind) My cleaner solution was to create a view model provider to use in xaml To do this, you can implement it as a MarkupExtension

public class ViewModelProvider : MarkupExtension
{
    #region ctor
    public ViewModelProvider()
    {
    }

    public ViewModelProvider(Type viewModelType)
    {
        ViewModelType = viewModelType;
    }
    #endregion ctor

    #region properties
    public Type ViewModelType { get; set; }
    #endregion properties

    #region methods
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return ((App)Application.Current).ServiceProvider.GetService(ViewModelType);
    }
    #endregion methods
}

Then in xaml, you can ask the viewmodel type you want to ViewModelProvider

DataContext="{local:ViewModelProvider local:MainViewModel}"
like image 3
Shenron Avatar answered Oct 17 '22 15:10

Shenron