Skip to main content
All docs
V22.1

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)));

View Example

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>
    

    View Example

  • 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:

    1. Register the service in the Dependency Injection container:

      container.RegisterSingleton(typeof(IMessageBoxService), typeof(DXMessageBoxService));
      
    2. 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.