具有依赖项的子ViewModel的WPF / MVVM导航

时间:2018-11-22 10:52:41

标签: wpf mvvm dependency-injection navigation inversion-of-control

我试图在WPF MDI应用程序中同时使用MVVM和依赖注入模式。 我正在使用虚拟机优先方法。

基本上,我的应用程序从App.xaml.cs类开始,如果我对这件事理解得很好,那应该是我的合成根目录(所有依赖项都已解决)。这是一个示例:

    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {          
            base.OnStartup(e);
            ...
            var login = new LoginView();
            login.DataContext = new LoginViewModel(Dependency1, Dependency2);

            loginView.ShowDialog();

            if (loginView.DialogResult.GetValueOrDefault())
            {
                 var app = new     MainWindow();
                 var mainVM = new MainViewModel(Dependency3, Dependency4);
                 app.DataContext = mainVM;
                 app.Show();
            }
        }
    }

到目前为止,没有问题,无论我使用DI容器还是手动使用依赖项注入,我都可以解决LoginViewModel和MainViewModel的依赖项。现在,让我们深入研究MainViewModel。

我受到Rachel Lim's approach的启发,并使用SelectedViewModel属性来获取/设置当前使用的ViewModel,该ViewModel使用DataTemplates绑定到其View。我将让您查看该链接以获取有关该过程的更多详细信息,因为它与此处的问题完全无关。 重要的是我的MainViewModel负责在需要时切换ViewModel。但是我的孩子ViewModels具有依赖项。这是一个简化的示例:

     class MainViewModel
     {

            private ViewModel1 vm1;
            private ViewModel2 vm2;                

            public MainViewModel(Dependency1, Dependency2)
            {
                 ...
            }

            ...

            // Method used by an ICommand to display the ViewModel1's associated View
            private void DisplayView1() 
            {
                 vm1 = new ViewModel1(Dependency3, Dependency4, Dependency5);

            // Method used by an ICommand to display the ViewModel2's associated View
            private void DisplayView2() 
            {
                 vm2 = new ViewModel2(Dependency3, Dependency6);
                 SelectedViewModel = vm2;
            }
            ...
     }

如您所见,有些子视图模型之间共享某些依赖项,而有些子视图模型之间则不共享。 我的问题是,我无法从合成根注入这些。到目前为止,我只找到了两种解决方案:

  • 具有两个合成根(类型):在App.xaml.cs中解析LoginViewModel和MainViewModel,在MainViewModel中解析子ViewModel。这意味着在使用IOC容器时,在两个类中都引用该容器。
  • 将子视图ViewModels作为MainViewModel的构造函数参数传递,并像对待其他任何依赖项一样对待它们。我的这种方法的问题在于,如果我有10个ViewModel,那么MainViewModel的构造函数将变得庞大。

我读到有人可以将工厂传递给MainViewModel并委托创建子ViewModel的责任,但是我看不到任何使用带有构造函数参数的child ViewModel的示例。

我不明白如何在不将所有子项的依赖项传递给MainViewModel的构造函数的情况下使用该方法,因此又不会使其变得庞大。

也许我看不到某些东西,但这对我来说似乎是一个死路。

请帮助我解决这个问题,并告诉我正确的方向。

谢谢。

1 个答案:

答案 0 :(得分:0)

直到现在我才意识到我把整个工厂的事情弄错了。

实际上,我使用的DI容器Ninject具有扩展名,可以解决我遇到的完全相同的问题。此扩展需要一个接口,该接口包含用于创建所需依赖关系(在本例中为ViewModels)并在幕后创建具体工厂的方法。我只是在滥用它,以为我需要以某种方式将所有依赖项传递给接口,同时它可以解析ViewModels本身,因为这些已经在容器中注册了。

现在,我所拥有的只是一个单一的组成根目录(我的App.xaml.cs),容器在其中解析LoginViewModel和MainViewModel。后者具有工厂接口作为依赖关系,用于解析所有子ViewModel,也由容器解析。无需额外引用容器!

非常感谢Coops的帮助!您一定会把我带到正确的轨道上!