Parece que no puedo encontrar una solución a este problema. He visto varias preguntas sobre esto, pero ninguna realmente me da una solución. Soy totalmente nuevo en Autofac y realmente no he hecho mucho WPF + MVVM, pero conozco los conceptos básicos.

Tengo una aplicación WPF (que usa ModernUI para WPF) a la que estoy tratando de agregar Autofac, y me cuesta descubrir cómo resolver mis servicios dentro de todas las vistas, ya que no tienen acceso a mi contenedor. Tengo una vista principal, que es mi punto de entrada, donde configuro mi contenedor:

public partial class MainWindow : ModernWindow
{
    IContainer AppContainer;

    public MainWindow()
    {

        SetUpContainer();

        this.DataContext = new MainWindowViewModel();
        InitializeComponent();

        Application.Current.MainWindow = this; 
    }

    private void SetUpContainer()
    {
        var builder = new ContainerBuilder();

        BuildupContainer(builder);

        var container = builder.Build();

        AppContainer = container;
    }

    private void BuildupContainer(ContainerBuilder builder)
    {
        builder.RegisterType<Logger>().As<ILogger>();
        ...
    }
}

El problema que tengo es descubrir cómo puedo resolver mi registrador y otros servicios dentro de mis otras vistas, donde inyecto todas mis dependencias a través del constructor ViewModel, de esta manera:

public partial class ItemsView : UserControl
{
    private ItemsViewModel _vm;

    public ItemsView()
    {
        InitializeComponent();

        IFileHashHelper fileHashHelper = new MD5FileHashHelper();
        ILibraryLoader libraryLoader = new LibraryLoader(fileHashHelper);
        ILogger logger = new Logger();

        _vm = new ItemsViewModel(libraryLoader, logger);
        this.DataContext = _vm;
    }
}

Algunas vistas tienen una cantidad ridícula de parámetros inyectados, y aquí es donde quiero que Autofac entre y me ayude a limpiar las cosas.

Estaba pensando en pasar el contenedor al ViewModel y almacenarlo como una propiedad en mi clase ViewModelBase, pero he leído que esto sería un antipatrón, e incluso entonces no sé si eso resolvería automáticamente mis objetos dentro de los otros ViewModels.

Logré armar una aplicación de consola simple usando Autofac

class Program
{
    static void Main(string[] args)
    {

        var builder = new ContainerBuilder();
        builder.RegisterType<Cleaner>().As<ICleaner>();
        builder.RegisterType<Repository>().AsImplementedInterfaces().InstancePerLifetimeScope();

        var container = builder.Build();

        using (var scope = container.BeginLifetimeScope())
        {

            ICleaner cleaner = container.Resolve<ICleaner>();
            cleaner.Update(stream);
        }
    }
}

Pero eso fue simple ya que tiene un único punto de entrada.

Me gustaría tener algunas ideas sobre cómo agregar Autofac a mi aplicación WPF. Estoy seguro de que estoy haciendo algo mal. Tu ayuda es apreciada.

11
Ben 29 abr. 2017 a las 00:26

3 respuestas

La mejor respuesta

Ampliando mi comentario anterior:

Utilizo Autofac con todas mis aplicaciones WPF MVVM, creo que es uno de los mejores marcos de DI: esta es mi opinión, pero creo que es válida.

Además, para mí, el PRISM debe evitarse el 99% del tiempo, es una ' solución que busca un problema ' y como la mayoría de las personas no construyen soluciones de tiempo de ejecución dinámicamente componibles en WPF, no es necesario, i ' Estoy seguro de que la gente no estará de acuerdo.

Al igual que cualquier patrón arquitectónico, hay una fase de configuración / configuración para el ciclo de vida de la aplicación, simplemente en su caso, antes de que se muestre la primera Vista (ventana), se realizará una configuración completa para Inyección de dependencias, Registro, Manejo de excepciones, Despachador gestión de hilos, temas, etc.

Tengo varios ejemplos de uso de Autofac con WPF \ MVVM, un par se enumeran a continuación, diría que mire el ejemplo de Simple.Wpf.Exceptions:

https://github.com/oriches/Simple.Wpf.Exceptions

https://github.com/oriches/Simple.Wpf.DataGrid

https://github.com/oriches/Simple.MahApps.Template

7
AwkwardCoder 1 may. 2017 a las 13:01

WPF no tiene una raíz de composición natural ni una fácil integración DI. Prism es un conjunto bastante común de bibliotecas destinadas específicamente a superar eso.

(Eso no es específico de Autofac: es una guía general para agregar DI a las aplicaciones WPF).

3
Travis Illig 28 abr. 2017 a las 23:32

Puede usar una técnica similar a su aplicación de consola:

class Program
{
    [STAThread]
    static void Main(string[] args)
    {
        var builder = new ContainerBuilder();
        builder.RegisterType<Cleaner>().As<ICleaner>();
        builder.RegisterType<Repository>().AsImplementedInterfaces().InstancePerLifetimeScope();

        // Add the MainWindowclass and later resolve
        build.RegisterType<MainWindow>().AsSelf();

        var container = builder.Build();

        using (var scope = container.BeginLifetimeScope())
        {
            var main = scope.Resolve<MainWindow>();
            main.ShowDialog();
        }
    }
}

Asegúrese de marcar Principal con [STAThread]. Luego, en las propiedades del proyecto, en la pestaña Aplicación, configure Startup object en la clase Programa.

Sin embargo, no estoy seguro de las implicaciones de no ejecutar App.Run() y de ejecutar MainWindow.ShowDialog() en su lugar.

Para hacer lo mismo con App.Run(), haga lo siguiente:

1) eliminar StartupUri="MainWindow.xaml" de App.xaml

2) Agregue lo siguiente a App.xaml.cs

protected override void OnStartup(StartupEventArgs e)
{
    var builder = new ContainerBuilder();
    builder.RegisterType<Cleaner>().As<ICleaner>();
    builder.RegisterType<Repository>().AsImplementedInterfaces().InstancePerLifetimeScope();

    // Add the MainWindowclass and later resolve
    build.RegisterType<MainWindow>().AsSelf();

    var container = builder.Build();

    using (var scope = container.BeginLifetimeScope())
    {
        var window = scope.Resolve<MainWindow>();
        window.Show();
    }
}
4
Swoogan 22 ago. 2018 a las 14:37