Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF view who leads to another using MVVM

Tags:

c#

mvvm

binding

wpf

I am trying to set up a navigation between views using a MVVM pattern. My application contains a MainWindow and two views with a button each. When I click on the button in the View1 I want to set up the View2 on the MainWindow.

I have found several tutorials witch explain how to navigate from a view to another with a button on the main window (simulate a tabControl), it works but it is not what I want.

I'm looking for something like :

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

My problem is if I do so, from the class View1_View I cannot access to the method SwitchToView2() if it is not static, and if it is static I lose the context of the MainWindow.

How should I proceed ? Thanks.

like image 918
C. Chen Avatar asked Jun 23 '17 08:06

C. Chen


2 Answers

I would recommend using a ContentControl to switch the part of your main view.

This could look like this (short form just to give you an idea; without INotifyPropertyChanged).

Create an empty interface of type ISwitchableViewModel.

Add a property to your main ViewModel

public property ISwitchableViewModel MyViewModel {get; set;}

Create two classes that implements the interface ISwitchableViewModel. Each for each view you want to show (View1 and View2 in your example) and call them ViewModel1 and ViewModel2.

When you press the button in your xaml set the MyViewModel to View1 or View2; whatever your logic is.

In your xaml add this at the place where you want to show the switchable content.

<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>

When you set the MyViewModel in your MainViewModelthe UI will show automatically the correct view for that viewmodel.

like image 91
Mighty Badaboom Avatar answered Nov 09 '22 19:11

Mighty Badaboom


You can achieve this by creating the views and assigning them to a content control.

Lets assume you have this content control in your main view.

<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>

You can then set the content in the code behind file of your main view.

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

Another solution would be to use an MVVM Framework light Caliburn.Micro, Prism etc, which essential do the same thing as the code snippet above, but hide the boilerplate code.

EDIT: I realized i didn't explicitly get to the second part of your question.

Usally one would need some kind of router which is able to control the navigation. For the sake of simplicity we use the main view as router. To access the main view, you need to inject it in each component.

This allows each of your submodels to access the main view.

This could be improved by using some kind of DI-Container or by a Mediator. A mediator would allow each component to send requests, which then are dispatched to the MainView, eliminating the direct dependency.

like image 23
Iqon Avatar answered Nov 09 '22 18:11

Iqon