将Autofac添加到WPF MVVM应用程序

Ben*_*Ben 9 c# wpf dependency-injection mvvm 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>();
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是弄清楚如何在我的其他视图中解析我的记录器和其他服务,在那里我通过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;
    }
}
Run Code Online (Sandbox Code Playgroud)

有些观点有大量的注入参数,这就是我想让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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

我想了解如何将Autofac添加到我的WPF应用程序中的一些想法.我确信我做错了什么.非常感谢您的帮助.

Awk*_*der 14

扩展我上面的评论:

我将 Autofac 与我所有的 WPF MVVM 应用程序一起使用,我相信它是更好的 DI 框架之一 - 这是我的意见,但我认为它是有效的。

同样对我来说,应该在 99% 的情况下避免 PRISM,这是一个“寻找问题解决方案”,并且由于大多数人不在 WPF 中构建动态可组合的运行时解决方案,因此不需要它,我相信人们会\会不同意.

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

我有几个使用 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

  • 我在想为什么我最近不想在执行 WPF\MVVM 时创建作用域容器,我得出的结论是 - 如果应用程序中的所有服务都注册为单例,因为它们是无状态的并且只有 ViewModel是按实例注册的,那么我不需要范围,因为服务将被共享,并且 ViewModel 应该及时处理 (2认同)

Swo*_*gan 8

您可以使用与控制台应用程序类似的技术:

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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

请务必用 标记 Main [STAThread]。然后在项目的属性中,在 Application 选项卡下,将 设置Startup object为 Program 类。

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();
    }
}
Run Code Online (Sandbox Code Playgroud)