将Autofac添加到WPF MVVM应用程序

时间:2017-04-28 21:26:56

标签: c# wpf mvvm dependency-injection autofac

我似乎无法找到解决此问题的方法。我已经看到了几个关于此的问题,但没有一个能给我一个解决方案。我对Autofac完全不熟悉,并且确实做了很多WPF + MVVM,但我知道基础知识。

我有一个WPF应用程序(使用ModernUI for WPF),我试图添加Autofac,我很难弄清楚如何在所有视图中解析我的服务,因为他们无法访问到我的容器。我有一个主视图,这是我的入口点,我设置了我的容器:

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>();
        ...
    }
}

我遇到的问题是弄清楚如何在我的其他视图中解析我的记录器和其他服务,在那里我通过ViewModel构造函数注入所有依赖项,如下所示:

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

有些观点有大量的注入参数,这就是我希望Autofac进入并帮助我清理的地方。

我正在考虑将容器传递给ViewModel并将其作为属性存储在我的ViewModelBase类中,但我已经读过这将是一个反模式,即便如此我也不知道如果这将自动解析其他ViewModels中的对象。

我设法使用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);
        }
    }
}

但这很简单,因为它有一个入口点。

我想了解如何将Autofac添加到我的WPF应用中的一些想法。我确定我做错了什么。感谢您的帮助。

3 个答案:

答案 0 :(得分:3)

扩展我的评论:

我在所有WPF MVVM应用程序中使用Autofac,我相信它是更好的DI框架之一 - 这是我的看法,但我认为它是有效的。

同样对我来说PRISM应该在99%的时间内避免使用,这是一个'解决方案寻找问题',因为大多数人都不在WPF中构建动态可组合的运行时解决方案,所以不需要,我相信人们会“不同意”。

与任何架构模式一样,应用程序生命周期有一个设置\配置阶段,在第一个View(窗口)显示之前简单地放在你的情况下,将完成依赖注入,日志记录,异常的整个设置处理,调度程序线程管理,主题等。

我有几个使用Autofac和WPF \ MVVM的例子,下面列出了几个,我想看一下Simple.Wpf.Exceptions示例:

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

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

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

答案 1 :(得分:3)

You can use a similar technique as your console application:

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

Be sure to mark Main with [STAThread]. Then in the project's properties, under the Application tab, set the Startup object to the Program class.

However, I am not certain of the implications of not running App.Run() and of running MainWindow.ShowDialog() instead.

To do the same using App.Run(), do the following:

1) delete StartupUri="MainWindow.xaml" from App.xaml

2) Add the following to 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();
    }
}

答案 2 :(得分:2)

WPF没有自然的组合根或简单的DI集成。 Prism是一组非常常见的库,专门用于为您提供桥接。

(这不是特定于Autofac的 - 它是向WPF应用添加DI的一般指导。)