Dependency Injection
- 3 minutes to read
#Bind a View to a View Model
To bind a view to a view model, create a MarkupExtension that resolves the correct ViewModel type:
public class DISource : MarkupExtension {
public static Func<Type, object, string, object> Resolver { get; set; }
public Type Type { get; set; }
public object Key { get; set; }
public string Name { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider) => Resolver?.Invoke(Type, Key, Name);
}
Register the resolver at the application startup:
protected override void OnStartup(StartupEventArgs e) {
base.OnStartup(e);
DISource.Resolver = Resolve;
}
object Resolve(Type type, object key, string name) {
if(type == null)
return null;
if(key != null)
return Container.ResolveKeyed(key, type);
if(name != null)
return Container.ResolveNamed(name, type);
return Container.Resolve(type);
}
Specify the DataContext in XAML in the following manner:
DataContext="{common:DISource Type=common:MainViewModel}"
#Examples
#Use POCO View Models with Dependency Injection
To use a POCO View Model in a Dependency Injection container, utilize the ViewModelSource.GetPOCOType method to register the POCO type generated at runtime:
container.RegisterType(typeof(IMainViewModel),
ViewModelSource.GetPOCOType(typeof(MainViewModel)));
#Use Services with Dependency Injection
The recommended technique to use DevExpress services with Dependency Injection varies depending on whether the service has an associated visual element.
If the service is attached to a specific visual element, add the following custom AttachServiceBehavior to register it:
public class AttachServiceBehavior : Behavior<DependencyObject> { public static readonly DependencyProperty AtachableServiceProperty = DependencyProperty.Register(nameof(AtachableService), typeof(ServiceBase), typeof(AttachServiceBehavior), new PropertyMetadata(null, OnAtachableServiceChanged)); static void OnAtachableServiceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { (e.OldValue as ServiceBase)?.Detach(); ((AttachServiceBehavior)d).AttachService(); } public ServiceBase AtachableService { get => (ServiceBase)GetValue(AtachableServiceProperty); set => SetValue(AtachableServiceProperty, value); } protected override void OnAttached() { base.OnAttached(); AttachService(); } protected override void OnDetaching() { base.OnDetaching(); AtachableService?.Detach(); } void AttachService() { if(AtachableService == null || AssociatedObject == null) return; if(AtachableService.IsAttached) AtachableService.Detach(); AtachableService.Attach(AssociatedObject); } }
Add a public property that corresponds to the service to the View Model:
public class MainViewModel { public INavigationService NavigationService { get; } public MainViewModel(INavigationService navigationService) => NavigationService = navigationService; }
Use the AttachServiceBehavior to attach the service to a visual element:
<dxwui:NavigationFrame> <dxmvvm:Interaction.Behaviors> <common:AttachServiceBehavior Service="{Binding NavigationService}"/> </dxmvvm:Interaction.Behaviors> </dxwui:NavigationFrame>
If the service does not need to be attached to a specific visual element (such as Message Box Services), you can use the following technique instead:
Register the service in the Dependency Injection container:
container.RegisterSingleton(typeof(IMessageBoxService), typeof(DXMessageBoxService));
Specify the corresponding View Model property:
public class MainViewModel { IMessageBoxService messageBoxService; public MainViewModel(IMessageBoxService dialogService) { this.messageBoxService = messageBoxService; } }
Tip
If you configure the service to work with a specific View, Dependency Injection is not recommended. Use the technique described in the following section instead: Implement Services in Your Application.