C# 如何使用核心项目和WPF应用程序之间的依赖项注入来更改页面?

C# 如何使用核心项目和WPF应用程序之间的依赖项注入来更改页面?,c#,.net,wpf,mvvm,dependency-injection,C#,.net,Wpf,Mvvm,Dependency Injection,我正在使用MVVM框架以及Ninject为依赖性注入构建一个WPF程序。我创建了两个项目,一个是.Net类库核心项目,用于其他.Net应用程序,另一个是WPF特定应用程序 目前,我正在使用带有属性的应用程序视图模型更改应用程序的页面CurrentPage是一种名为ApplicationPage的Enum类型,包含我的应用程序中的不同页面。在我的WPF应用程序的主窗口中有一个框架,其内容绑定到当前页面属性,并使用值转换器将值转换为不同的自定义页面,我使用开关语句制作,如下所示: if (value

我正在使用
MVVM
框架以及
Ninject
依赖性注入构建一个
WPF
程序。我创建了两个项目,一个是
.Net类库
核心项目,用于其他
.Net
应用程序,另一个是
WPF
特定应用程序

目前,我正在使用带有
属性的
应用程序视图模型
更改应用程序的页面
CurrentPage
是一种名为
ApplicationPage
Enum
类型,包含我的应用程序中的不同页面。在我的WPF应用程序的主窗口中有一个框架,其
内容
绑定到
当前页面属性
,并使用值转换器将值转换为不同的
自定义页面
,我使用
开关
语句制作,如下所示:

if (value is ApplicationPage)
    switch ((ApplicationPage)value)
    {
        case ApplicationPage.PageOne:
            return new PageOne();
        case ApplicationPage.PageTwo:
            return new PageTwo();
        default:
            throw Exception;
    }
}
我想使用
构造函数
注入
将这些页面的
视图模型
传递到
转换器
页面的
构造函数
,使用
视图模型
,这些视图模型又被
注入
应用程序视图模型
类,有点像这样:

case ApplicationPage.PageOne:
    return new PageOne(PageOneViewModel);
我的第一个想法是,是否有某种方法可以使
CurrentPage
属性实际上成为一个特定的
ViewModel
,并在其上执行
开关
ViewModel
,从而
转换器将
视图模型
转换为
页面

但是,
CurrentPage
类型是一个问题,因为它必须设置为一个
ViewModels
,因此无法获取不同的
ViewModel
的值,只剩下一个
ViewModel

我的想法是:是否有办法将
视图模型
传递到
转换器
?或者我可以将
CurrentPage
设置为
IViewModelFactory
并从工厂在转换器内创建
ViewModel
?在这种情况下,如何更改
CurrentPage
的值以更改应用程序中的页面


在遵循这一逻辑的同时,是否有一种方法可以坚持依赖关系,还是有另一种方法,我需要重新考虑我的代码以进行页面更改?不幸的是,我看到的大多数示例都属于所谓的
ServiceLocator
反模式。

答案是使用如下数据模板

<Window.Resources>
    <DataTemplate x:Key="View1Template" DataType="{x:Type local:MainWindowViewModel}">
        <!-- Custom control style with a Data Context set to a Viewmodel 
        object in the MainWindowViewModel -->
        <local:CustomPage1 DataContext="{Binding CustomPage1ViewModel}" />
    </DataTemplate>

    <DataTemplate x:Key="View2Template" DataType="{x:Type local:MainWindowViewModel}">
        <!-- Custom control style with a Data Context set to a Viewmodel 
        object in the MainWindowViewModel -->
        <local:CustomPage2 DataContext="{Binding CustomPage2ViewModel}" />
    </DataTemplate>
</Window.Resources>

CurrentView
是一个属性,可以在代码中更改为
Trigger
UI
中的更改-可以设置为
PageNames
Enum

不,不,不。老实说,这里有一个争论,但我给你两分。当涉及到数据绑定和视图模型时,DI和导航不应该是同一个。当然像Prism这样的产品也允许这样做,但我不同意这种方法。您当然可以注入视图,但我个人建议不要以这种方式注入ViewModel或控制导航。在MVC中,您允许控制器指示视图和导航,但在MVVM中,您应该对导航做出反应。换句话说,将视图模型编写成更像绑定端点,并……进行反应性导航。在视图层中构建导航。这将分离关注点,并允许在任何层上对系统进行更轻松的扩展/选项/更改。我喜欢您的导航视图模型方法,您可以在视图层中使用独特的MVVM样式的导航,但从逻辑上讲,它不需要,而且IMO不应该依赖于ViewModel层。这是一个很长的讨论,在网上有争议,所以我不会说这是必须的,但我在这里用各种方法做了很多工作,从我的个人经验可以告诉你,我不会再选择这样做了。我相信,分离这个逻辑也会解决你的问题。如果您有一个独特的视图系统,请将其视为可视模型的附件。不要假装知道ViewModel层中的视图,也不要假装视图始终相同。用任何视图都可以附加和工作的想法来构建它,无论它们如何使用VM。谢谢你们,这非常有帮助。使用数据模板似乎是前进的方向。我已经找到了结合你两个答案的解决方案,效果非常好!我之所以有一个单独的导航视图模型,只是为了让我能够在其他项目中使用它,而不是在这个项目中,但我想每个项目都有自己的导航需求。
<ContentControl Content="{Binding}">
    <ContentControl.Style>
        <Style TargetType="{x:Type ContentControl}">

            <!-- The Default/initial View being shown -->
            <Setter Property="ContentTemplate" Value="{StaticResource View1Template}" />

            <!-- Triggers bound to the CurrentView Property -->
            <Style.Triggers>
                <DataTrigger Binding="{Binding CurrentView}" Value="1">
                    <Setter Property="ContentTemplate" Value="{StaticResource View1Template}" />
                </DataTrigger>
                <DataTrigger Binding="{Binding CurrentView}" Value="2">
                    <Setter Property="ContentTemplate" Value="{StaticResource View2Template}" />
                </DataTrigger>
            </Style.Triggers>

        </Style>
    </ContentControl.Style>
</ContentControl>