π
Hour 4 β Dependency Injection (DI) & Navigation Patterns
π§° 1. What is Dependency Injection?
Dependency Injection (DI) is a technique where objects (ViewModels, Services)
receive their dependencies instead of creating them manually. It helps:
- π¦ Reduce tight coupling
- π Promote reuse & testability
- π§ͺ Make ViewModels easy to Unit Test
- π§Ή Keep your code cleaner
Why DI in MVVM?
- π ViewModels should NOT create their own services
- π All dependencies should be injected
- β‘ MAUI/WPF already supports DI via ServiceCollection
ποΈ 2. Registering ViewModels and Services in DI (MAUI)
In .NET MAUI, ViewModels and Services are registered in MauiProgram.cs.
Example registration:
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder.Services.AddSingleton<HomeViewModel>();
builder.Services.AddTransient<DetailViewModel>();
builder.Services.AddSingleton<IDataService, DataService>();
return builder.Build();
}
- π Singleton: same instance reused
- π Transient: new instance each time
π 3. Constructor Injection in ViewModels
Instead of creating services manually, DI injects them through the constructor.
Example:
public class HomeViewModel : ObservableObject
{
private readonly IDataService dataService;
public HomeViewModel(IDataService service)
{
dataService = service;
}
}
β Now the ViewModel is fully testable and not dependent on concrete classes.
π 4. Creating Services for ViewModels
Example service interface:
public interface IDataService
{
Task<string> GetMessageAsync();
}
Implementation:
public class DataService : IDataService
{
public Task<string> GetMessageAsync()
{
return Task.FromResult("Hello from service!");
}
}
π€ This service is injected into the ViewModel automatically via DI.
β‘οΈ 5. Navigation in MVVM (MAUI)
In MVVM, pages typically don't navigate themselves β ViewModels request navigation.
There are two common patterns:
- π Using Shell Navigation (recommended)
- π Using a custom NavigationService
π 6. Shell Navigation from ViewModel
ViewModel example:
public partial class HomeViewModel : ObservableObject
{
[ICommand]
private async Task GoToDetails()
{
await Shell.Current.GoToAsync("details");
}
}
XAML:
<Button Text="Open Details" Command="{Binding GoToDetailsCommand}" />
β This navigates to a page registered as "details".
π§ 7. Passing Parameters During Navigation
ViewModel navigation:
await Shell.Current.GoToAsync("details?itemId=10");
Receiving ViewModel:
[QueryProperty(nameof(ItemId), "itemId")]
public partial class DetailViewModel : ObservableObject
{
[ObservableProperty]
private int itemId;
}
π© The parameter is auto-injected into the ViewModel.
π§ 8. NavigationService Pattern (Optional Advanced)
Sometimes applications implement a custom navigation service:
public interface INavigationService
{
Task NavigateToAsync(string route);
}
Implementation:
public class NavigationService : INavigationService
{
public Task NavigateToAsync(string route)
{
return Shell.Current.GoToAsync(route);
}
}
Inject into ViewModel:
public class HomeViewModel
{
private readonly INavigationService nav;
public HomeViewModel(INavigationService navigation)
{
nav = navigation;
}
}
β Best for large apps.
π οΈ 9. Hour 4 Hands-On Tasks
- π§± Build a simple service: IDataService
- π Register it as Singleton using DI
- π Inject service into a ViewModel
- π¨ Fetch data using the service
- β‘οΈ Implement Shell navigation from ViewModel
- π¨ Pass parameters to another ViewModel
π 10. Hour 4 Practice Example (Recommended)
public partial class HomeViewModel : ObservableObject
{
private readonly IDataService dataService;
[ObservableProperty]
private string message;
public HomeViewModel(IDataService service)
{
dataService = service;
LoadMessage();
}
private async void LoadMessage()
{
Message = await dataService.GetMessageAsync();
}
[ICommand]
private async Task GoToDetails()
{
await Shell.Current.GoToAsync("details");
}
}
β This ViewModel fetches data and handles navigation cleanly.
π Hour 4 Goals Completed
- π You understand Dependency Injection
- π¦ You can register ViewModels and Services
- π‘ You can inject services into ViewModels
- β‘οΈ You can navigate between pages using ViewModels
- π¨ You know how to pass parameters via navigation
- π§ You know NavigationService pattern
π Hour 4 β Dependency Injection & Navigation Quiz
π Section A β Multiple Choice Questions
-
What is the main purpose of Dependency Injection?
a) To speed up UI animations
b) To hide errors
c) To supply dependencies to classes instead of creating them manually
d) To store application settings
-
In .NET MAUI, where do you register ViewModels and Services for DI?
a) AppShell.xaml
b) App.xaml.cs
c) MauiProgram.cs
d) MainPage.xaml.cs
-
Which lifetime creates a new instance every time itβs requested?
a) Singleton
b) Scoped
c) Transient
d) Recycled
-
What is injected into a ViewModel when using DI?
a) Default UI theme
b) Services required by the ViewModel
c) Hardware drivers
d) Page instances
-
How does a ViewModel navigate using Shell?
a) Using GoToPage()
b) Using NavigateAsync()
c) Using Shell.Current.GoToAsync()
d) Using PageManager.Go()
π§ Section B β True or False
- True / False: DI improves testability by removing direct object creation.
- True / False: Singleton services create new instances on every request.
- True / False: ViewModels should avoid referencing UI controls.
- True / False: Shell navigation allows passing parameters between pages.
- True / False: Constructor injection is the most common DI pattern in MVVM.
βοΈ Section C β Short Answer Questions
- What is the major benefit of registering a service as Singleton?
- Explain why creating services inside ViewModels is considered bad practice.
- Write the simplest possible DI constructor for a ViewModel that receives an IDataService.
- Explain how to pass a parameter using Shell navigation.
- What is the role of a NavigationService in MVVM applications?
π» Section D β Code Interpretation
Given:
public class HomeViewModel
{
private readonly IDataService data;
public HomeViewModel(IDataService service)
{
data = service;
}
}
- What DI concept is being used here?
- Who is responsible for creating the IDataService instance?
- Is the ViewModel dependent on the concrete implementation?
π§ Section E β Navigation Logic
Given:
await Shell.Current.GoToAsync("details?itemId=15");
- What value is passed as a parameter?
- Which ViewModel attribute is needed to receive the parameter?
- What must the receiving ViewModel's property name match?
π Hour 4 β Dependency Injection & Navigation Quiz Answer Key
β
Section A β Multiple Choice Answers
- c) To supply dependencies to classes instead of creating them manually
- c) MauiProgram.cs
- c) Transient
- b) Services required by the ViewModel
- c) Using Shell.Current.GoToAsync()
π§ Section B β True or False Answers
- True β DI improves testability.
- False β Singleton creates only one instance.
- True β ViewModels should avoid UI references.
- True β Shell supports parameter passing.
- True β Constructor injection is most common in MVVM.
βοΈ Section C β Short Answer Solutions
-
Singleton benefit: Only one shared instance is created for the whole app.
-
Creating services inside ViewModels is bad because it creates tight coupling and makes testing difficult.
-
Simplest constructor injection:
public HomeViewModel(IDataService dataService)
{
DataService = dataService;
}
-
Pass a parameter using:
Shell.Current.GoToAsync("details?itemId=10");
-
A NavigationService centralizes and manages navigation logic, making ViewModels simpler.
π» Section D β Code Interpretation Answers
- Constructor Injection is used.
- The DI container (ServiceCollection) creates the IDataService instance.
-
No β the ViewModel depends on the interface (IDataService), so it is loosely coupled.
π§ Section E β Navigation Logic Answers
- itemId = 15 is passed.
- [QueryProperty] attribute is required.
-
The property name must match the QueryProperty attribute mapping.
π 4 Answer Key Complete