C# 将Autofac添加到WPF MVVM应用程序

C# 将Autofac添加到WPF MVVM应用程序,c#,wpf,mvvm,dependency-injection,autofac,C#,Wpf,Mvvm,Dependency Injection,Autofac,我似乎找不到解决这个问题的办法。关于这一点,我见过几个问题,但没有一个能真正给我答案。我对Autofac完全陌生,并没有真正做过太多WPF+MVVM,但了解基本知识 我有一个WPF应用程序(使用ModernUI for WPF),我正试图将Autofac添加到该应用程序中,我很难弄清楚如何在所有视图中解析我的服务,因为它们无法访问我的容器。我有一个主视图,这是我的入口点,在这里我设置了我的容器: public partial class MainWindow : ModernWindow {

我似乎找不到解决这个问题的办法。关于这一点,我见过几个问题,但没有一个能真正给我答案。我对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>();
        ...
    }
}
有些视图有大量的注入参数,这就是我希望Autofac介入并帮助我清理的地方

我曾考虑将容器传递给ViewModel,并将其作为属性存储在ViewModelBase类中,但我已经了解到这将是一种反模式,即使如此,我也不知道这是否会自动解析其他ViewModel中的对象

我设法用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);
        }
    }
}
类程序
{
静态void Main(字符串[]参数)
{
var builder=new ContainerBuilder();
builder.RegisterType().As();
builder.RegisterType();
var container=builder.Build();
使用(var scope=container.BeginLifetimeScope())
{
ICleaner cleaner=container.Resolve();
更新(流);
}
}
}
但这很简单,因为它只有一个入口点


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

WPF没有自然的合成根或简单的DI集成。是一组非常常见的库,专门为您搭建这一桥梁


(这不是Autofac特有的-这是将DI添加到WPF应用程序的一般指南。)

扩展我的上述评论:

我在所有WPF MVVM应用程序中都使用Autofac,我认为它是一个更好的DI框架——这是我的观点,但我认为它是有效的

另外,对我来说,PRISM应该在99%的时间内避免使用,它是一种“寻找问题的解决方案”,而且由于大多数人不在WPF中构建动态可组合的运行时解决方案,所以不需要它,我相信人们会不同意

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

我有几个将Autofac与WPF\MVVM一起使用的示例,下面列出了几个示例,我想说看看Simple.WPF.Exceptions示例:


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

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

我读过关于Prism的书,也读过将它应用于现有应用程序(基本上是重写它)是一项艰巨的任务,所以我认为这不适合我的解决方案。我有一个工作应用程序,它是完全DI的,带有单元测试,但我希望使用Autofac之类的工具来清理注入的参数。Prism看起来很棒,谢谢@Ben-如果您已经运行了DI和测试,您可能会惊讶于“重写”更改是多么容易实现。以一种不必编写新测试(重构)的方式处理经过测试的代码库比您预期的要快得多。人们忘记了TDD红绿重构的“重构”部分,这是一个悲剧——这也是有趣的部分,最终结果是维护的乐趣。但是,如果您的团队成员不愿意学习框架,那么这很难(在许多情况下并不实用)。我在所有DI中都使用Autofac,下面是我使用WPF\MVVM的一个示例,这可能正是我想要的。从我所看到的,您使用应用程序OnStartup作为入口点,并从那里构建容器。这对我来说似乎很容易做到。我不清楚的是,你是如何从那里设置你的范围的?您的范围在哪里处理?我指的是你的Simple.Wpf.Exceptions项目。是的,一切都从启动、设置异常处理、启动引导程序(DI)和许多调试/诊断工作开始。你所说的范围是什么意思?如果你指的是范围DI容器中的范围,通常我不使用它们,我很久以前就用过,但现在我发现,若我对体系结构和实现(MVVM)很勤奋,那个么我通常就不需要它们了。虽然我已经给出了一个例子,说明我可能在MVVM应用程序中设置了容器的作用域,但它已经很久没有更新了,因此nuget引用非常旧-我在想为什么我最近不想在执行WPF\MVVM时创建作用域容器,我得出的结论是——如果应用程序中的所有服务都注册为单例,因为它们是无状态的,并且每个实例只注册ViewModels,那么我就不需要范围,因为服务将被共享,ViewModels应该被及时处理
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();
        }
    }
}
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();
    }
}