使用MVVM模式的WPF视图如何导航到另一个视图

6
我正在尝试使用MVVM模式在视图之间设置导航。我的应用程序包含一个MainWindow和两个带有按钮的视图。当我点击View1中的按钮时,我想在MainWindow上设置View2。
我找到了几个教程,它们解释了如何使用主窗口上的按钮从一个视图导航到另一个视图(模拟TabControl),它可以工作,但这不是我想要的。
我正在寻找像这样的东西:
View1_View.xaml.cs:
public partial class View1_View : UserControl
{
    private View1_ViewModel _viewModel = new View1_ViewModel();

    public View1_View()
    {
        InitializeComponent();
    }

    private void Btn_SwitchToView2_Click(object sender, RoutedEventArgs e)
    {
        MainWindow.SwitchToView2();
    }
}

MainWindow.xaml.cs :

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new View1_View();
    }

    public void SwitchToView2()
    {
        this.DataContext = new View2_View();
    }
}

我的问题是,如果我这样做,从类中,如果方法不是静态的,则无法访问它,如果它是静态的,我将失去MainWindow的上下文。

我该怎么办? 谢谢。


2
这里的 this.DataContext = new View2_View(); 应该指向一个 viewmodel 而不是一个视图,如果你要遵循 MVVM。 - user585968
2个回答

3
我建议使用ContentControl来切换主视图的部分。这可能看起来像这样(仅为了给您提供一个想法的简短形式; 不包括INotifyPropertyChanged)。
创建一个类型为ISwitchableViewModel的空接口。
在您的主要ViewModel中添加属性。
public property ISwitchableViewModel MyViewModel {get; set;}

创建两个类来实现接口ISwitchableViewModel,每个类对应一个要显示的视图(例如你的示例中的View1View2),并将它们命名为ViewModel1ViewModel2
当你在xaml中按下按钮时,将MyViewModel设置为View1View2,具体逻辑视情况而定。
在xaml文件中添加以下代码以显示可切换的内容。
<ContentControl Content="{Binding MyViewModel}">
    <ContentControl.Resources>
        <DataTemplate DataType="{x:Type viewModel:ViewModel1}">
            <view:View1 />
        </DataTemplate>
        <DataTemplate DataType="{x:Type viewModel:ViewModel2}">
            <view:View2 />
        </DataTemplate>
    </ContentControl.Resources>
</ContentControl>

当您在MainViewModel中设置MyViewModel时,UI将自动显示适用于该视图模型的正确视图。

1
你可以通过创建视图并将其分配给内容控件来实现此目的。
假设您在主视图中拥有此内容控件。
<Window x:Class="MVVM.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:MVVM"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
    <StackPanel>
         <Button x:Name="ChangeView" Click="SwitchToSecondView" Content="Set View"></Button>
         <ContentControl x:Name="MainContent"></ContentControl>
    </StackPanel>
</Window>

您可以在主视图的代码后台文件中设置内容。

public partial class MainWindow : Window
{
   public MainWindow()
   {
      InitializeComponent();
   }

   public void SwitchToSecondView(object sender, outedEventArgs e)
   {
      var view = new SecondView();
      var model = new SecondViewModel(this);
      view.DataContext = model;
      MainContent.Content = view;
   }

   public void SwitchToThirdView(object sender, outedEventArgs e)
   {
      var view = new ThirdView();
      var model = new ThirdViewModel(this);
      view.DataContext = model;
      MainContent.Content = view;
   }
}

另一种解决方案是使用MVVM框架,如Caliburn.Micro、Prism等,它们本质上与上面的代码片段执行相同的操作,但隐藏了样板代码。

编辑:我意识到我没有明确回答你问题的第二部分。

通常需要某种路由器来控制导航。为了简单起见,我们使用主视图作为路由器。要访问主视图,您需要在每个组件中注入它。

这允许您的每个子模型都可以访问主视图。

这可以通过使用某种DI容器或中介者来改进。中介者将允许每个组件发送请求,然后将其调度到MainView,消除直接依赖。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接