Dependency Injection
- 3 minutes to read
Bind a View to a View Model
Configure the application dependency injection container and assign it to the IocServiceProvider.Default service at startup. The IocExtension can resolve MainViewModel from XAML during initialization:
using DevExpress.Mvvm;
using Microsoft.Extensions.DependencyInjection;
using MvvmApp.ViewModels;
namespace MvvmApp {
public partial class App : Application {
// ...
protected override void OnStartup(StartupEventArgs e) {
IServiceProvider services = new ServiceCollection()
.AddTransient<MainViewModel>()
.BuildServiceProvider();
// Configure the global provider before WPF starts loading StartupUri/XAML
// The {dxmvvm:Ioc ...} config can resolve types in XAML during initialization
IocServiceProvider.Default.ConfigureServices(services);
base.OnStartup(e);
var mainWindow = new MainWindow();
MainWindow = mainWindow;
mainWindow.Show();
}
}
}
Declare a MainViewModel class with a read-only Message property that contains text for UI binding:
namespace MvvmApp.ViewModels {
public sealed class MainViewModel {
public string Message { get; } = "DI works through the IocExtension";
}
}
Use the IocExtension to resolve a MainViewModel from the configured dependency injection container. The window sets the resolved MainViewModel instance as DataContext, so the TextBlock can bind to the Message property:
<dx:ThemedWindow
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core"
xmlns:dxmvvm="http://schemas.devexpress.com/winfx/2008/xaml/mvvm"
xmlns:vm="clr-namespace:MvvmApp.ViewModels"
DataContext="{dxmvvm:Ioc Type={x:Type vm:MainViewModel}}">
<Grid>
<TextBlock Text="{Binding Message}"/>
</Grid>
</dx:ThemedWindow>
Examples
Services
POCO
Use POCO View Models with Dependency Injection
To use a POCO View Model in a dependency injection container, register the View Model type in the container:
services.AddTransient(typeof(MainViewModel));
Use Services with Dependency Injection
We recommend two different DevExpress service usage techniques with dependency injection depending on whether the required service is associated with a visual element.
Attached Service
If the service is attached to a specific visual element, add the following custom
AttachServiceBehavior:public class AttachServiceBehavior : Behavior<DependencyObject> { public static readonly DependencyProperty AttachableServiceProperty = DependencyProperty.Register( nameof(AttachableService), typeof(ServiceBase), typeof(AttachServiceBehavior), new PropertyMetadata(null, OnAttachableServiceChanged)); static void OnAttachableServiceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { (e.OldValue as ServiceBase)?.Detach(); ((AttachServiceBehavior)d).AttachService(); } public ServiceBase AttachableService { get => (ServiceBase)GetValue(AttachableServiceProperty); set => SetValue(AttachableServiceProperty, value); } protected override void OnAttached() { base.OnAttached(); AttachService(); } protected override void OnDetaching() { base.OnDetaching(); AttachableService?.Detach(); } void AttachService() { if(AttachableService == null || AssociatedObject == null) return; if(AttachableService.IsAttached) AttachableService.Detach(); AttachableService.Attach(AssociatedObject); } }Add a public property that maps the service to the view model:
public class MainViewModel { public INavigationService NavigationService { get; } public MainViewModel(INavigationService navigationService) => NavigationService = navigationService; }Use the
AttachServiceBehaviorproperty to attach the service to a visual element:<dxwui:NavigationFrame> <dxmvvm:Interaction.Behaviors> <common:AttachServiceBehavior AttachableService="{Binding NavigationService}"/> </dxmvvm:Interaction.Behaviors> </dxwui:NavigationFrame>
Unattached Service
If the service does not need to be attached to a specific visual element (such as Message Box Services), you can register the service in the dependency injection container:
services.AddSingleton<IMessageBoxService, DXMessageBoxService>();Specify the corresponding
ViewModelproperty:public class MainViewModel { readonly IMessageBoxService messageBoxService; public MainViewModel(IMessageBoxService messageBoxService) { this.messageBoxService = messageBoxService; } }
Tip
If you configure the service to work with an individual View, dependency injection is not recommended. Use the technique described in the following section instead: Implement Services in Your Application.