Building on the previous postings, today I want to discuss the magic of Dependency Injection (DI)
Dependency Injection makes for cleaner and more testable code. We’ll get into testing and Mocks in a later blog post, but using DI allows you to substitute a mock service for a real one. In any case, it is magical.
Even though this is powerful, this posting will be short, because once you know how to do it, it is very easy.
Let’s look at BuddyPreferences. This is the page that lists all the preferences of a specific buddy. We start, in BuddyPreferences.xaml.cs by creating BuddyPreferencesViewModel so that it can be our BindingContext. We pass the ViewModel into the constructor. Here is the complete class:
public partial class BuddyPreferences : ContentPage
{
private BuddyPreferencesViewModel vm;
public BuddyPreferences(BuddyPreferencesViewModel vm)
{
this.vm = vm;
BindingContext = vm;
InitializeComponent();
}
}
As you can see, the BuddyPreferenceViewModel is passed in. But where does it come from? Who passes it in? That is the magic of an InversionOfControl (IOC) container, which .NET MAUI provides to you for free. All you need do is register all your pages, viewmodels and services in MauiProgram.cs:
var builder = MauiApp.CreateBuilder();
builder
.UseTelerik()
.UseMauiApp<App>()
.UseMauiCommunityToolkit()
.ConfigureFonts(fonts =>
{
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
});
// Pages
builder.Services.AddTransient<About>();
builder.Services.AddTransient<BuddyDetail>();
builder.Services.AddTransient<BuddyList>();
builder.Services.AddTransient<View.Preferences>();
// Services
builder.Services.AddSingleton<BuddyService>();
builder.Services.AddTransient <PreferencesService>();
// ViewModel
builder.Services.AddTransient<BuddyListViewModel>();
builder.Services.AddTransient<BuddyDetailViewModel>();
builder.Services.AddTransient<BuddyPreferencesViewModel>();
return builder.Build();
As you can see in this excerpt of Mauiprogram.cs, we’ve registered the BuddyPreferences page, and the viewModel (Note, the reason we write View.Preferences is to avoid a name collision).
With that in place, the BuddyPreferencesViewModel is supplied by .NET MAUI to the constructor of BuddyPreferences, as shown above. You do not ever new-up a BuddyPreferencesViewModel – the creation of the VM is taken care of for you.
Notice that BuddyPreferencesViewModel is marked with AddTransient. There are two ways to add a page/service/view to the IoC – Transient and Singleton. If you make something a singleton as we do with the BuddyService then each time you get the service you get the same one. If you mark it transient, then each time you get it, you get a new one. General guidence is to use Singleton if you’ll be getting that object a lot (save memory) or if you need to preserve state.
The ViewModel itself depends on having an instance of BuddyService. We give it to BuddyPreferencesViewModel in the same way, by injecting it into the constructor
private readonly BuddyService buddyService;
public BuddyPreferencesViewModel(BuddyService buddyService)
{
ShowActivityIndicator = true;
this.buddyService = buddyService;
}
Go back and look at the creation of the BuddyPreferencesViewModel. No where is a new BuddyService “newed-up” and passed in. The Buddy Service is there because you registered it and so MAUI knows where to find it and what it depnds on. MAUI will not only create the BuddyService, but also any other classes in the chain of dependencies.
You’ll see this pattern throughout ForgetMeNot, and any well designed MaUI program.
Note: This pattern and Inversion of Control containers have been around for a long time. What is very nice here is that it is all built into MAUI.
아름다운스웨디시업소