I want to do a navigation bar and the most common way to navigate in WPF application is using UserControls and data templates but if I using dependency injection i can´t use xaml like this:
<Window x:Class="MyApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyApp"
Title="MainWindow" Height="200" Width="300">
<Grid>
<local:MyUserControl />
</Grid>
</Window>
WPF creates the instance of user control and I can´t manage that with my dependency injection container, for example I do this with my MainWindow but I want to do some similar with user control:
public App()
{
AppHost = Host.CreateDefaultBuilder()
.ConfigureServices((hostContext, services) =>
{
services.AddSingleton<MainWindow>();
})
.Build();
}
protected override async void OnStartup(StartupEventArgs e)
{
await AppHost!.StartAsync();
MainWindow = AppHost.Services.GetRequiredService<MainWindow>();
MainWindow.Show();
base.OnStartup(e);
}
Manage User Controls of WPF with dependency injection
You can create a markup extension to resolve UserControl from a DI container.
Ioc.cs
public class Ioc : MarkupExtension {
public static Func<Type, object> Resolver { get; set; }
public Type Type { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider) => Resolver?.Invoke(Type)!;
}
App.cs
public partial class App : Application {
//...
protected override void OnStartup(StartupEventArgs e) {
//...
//Configure the resolver so that Ioc knows how to create your UserControls
Ioc.Resolver = (type) => type != null ? host.Services.GetRequiredService(type) : null!;
}
}
MainWindow.xaml
<Window xmlns:in="clr-namespace:MySuperApp.Infrastructure"
xmlns:views="clr-namespace:MySuperApp.Views">
<Grid>
<ContentControl Content="{in:Ioc Type={x:Type views:MyUserControl}}"/>
</Grid>
<Window>
With this technique, you can easily resolve any UserControl (or its ViewModel) by its type.