5

I Know that my problem is a common one but every solution I found is not the one I really need. Here is my problem : I want to be able to switch between different usercontrol in the mainWindow. All the solution I found consist of having a menu in the main window and every button brings the corresponding userControl, like this exemple : https://rachel53461.wordpress.com/2011/12/18/navigation-with-mvvm-2/

But what i want is more like : at the begining, the mainwindows has the UserControl1 into it. In the userControl1 there would be 1 buttons who change the content of the mainWindow with a new userControl (userControl2 for instance)

enter image description here

the xaml of mainWindow

<Window x:Class="DataTemplateSO_Learning.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:DataTemplateSO_Learning"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>       
        <DataTemplate DataType="{x:Type local:EmployeeViewModel}">
            <local:EmployeeView/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:DepartmentViewModel}">
            <local:DepartmentView/>
        </DataTemplate>
        <DataTemplate DataType="{x:Type local:MenuViewModel}">
            <local:MenuView/>
        </DataTemplate>
    </Window.Resources>
    <DockPanel LastChildFill="True">
        <ContentControl x:Name="Pages" DockPanel.Dock="Right" Content="{Binding SelectedViewModel}"/>
    </DockPanel>
</Window>

the cs of my mainWindow :

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        Pages.Content = new MenuView();
        this.DataContext = new NavigationViewModel();
    }
}

the xaml of my first page :

<UserControl x:Class="DataTemplateSO_Learning.MenuView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:DataTemplateSO_Learning"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <DockPanel LastChildFill="True">
        <StackPanel x:Name="navigation" DockPanel.Dock="Left" VerticalAlignment="Center">
            <Button Content="Employee" Command="{Binding EmpCommand}"></Button>
            <Button Content="Department" Command="{Binding DeptCommand}"></Button>
        </StackPanel>
    </DockPanel>
</UserControl>

my first page View :

public partial class MenuView : UserControl
{
    public MenuView()
    {
        InitializeComponent();
        this.DataContext = new MenuViewModel();
    }
}

the viewModel of my first page :

class MenuViewModel 
{
    public ICommand EmpCommand { get; set; }
    public ICommand DeptCommand { get; set; }

    public MenuViewModel()
    {
        EmpCommand = new BaseCommand(OpenEmp);
        DeptCommand = new BaseCommand(OpenDept);
    }

    private void OpenEmp(object obj)
    {
        SelectedViewModel = new EmployeeViewModel();
    }
    private void OpenDept(object obj)
    {
        SelectedViewModel = new DepartmentViewModel();
    }
}

of course he doesn't know "SelectedViewModel" because it's bind to the control of mainWindow

my navigationViewModel :

class NavigationViewModel : INotifyPropertyChanged
{
    private object selectedViewModel;

    public object SelectedViewModel
    {
        get
        {
            return selectedViewModel;
        }
        set
        {
            selectedViewModel = value;
            OnPropertyChanged("SelectedViewModel");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(string propName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propName));
        }
    }

}

Thank you very much for your help !

Json
  • 153
  • 2
  • 7
  • 17
  • 1
    You need to use data templates and associate them with your embedded view models. Then you need to create a command for the button to trigger on the main form's view model which updates the "current" embedded view model and calls notify property changed. Where are your view models? Show us the code please. It sounds like you need to start from the beginning, i.e. find a "WPF and MVVM for beginners" tutorial. That's how I got started. – rory.ap Feb 14 '17 at 15:23
  • Share the code you tried and let us know if there is any specific issue you are facing. – Versatile Feb 14 '17 at 15:24
  • @rory.ap here is my code ( above) – Json Feb 14 '17 at 15:40

1 Answers1

6

You could for example inject the MenuView or MenuViewModel with a reference to the MainViewModel:

MainWindow.xaml.cs:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        var viewModel = new NavigationViewModel();
        viewModel.SelectedViewModel = new MenuViewModel(viewModel);
        this.DataContext = viewModel;
    }
}

MenuViewModel.cs:

class MenuViewModel
{
    public ICommand EmpCommand { get; set; }
    public ICommand DeptCommand { get; set; }

    private readonly NavigationViewModel _navigationViewModel;

    public MenuViewModel(NavigationViewModel navigationViewModel)
    {
        _navigationViewModel = navigationViewModel;
        EmpCommand = new BaseCommand(OpenEmp);
        DeptCommand = new BaseCommand(OpenDept);
    }

    private void OpenEmp(object obj)
    {
        _navigationViewModel.SelectedViewModel = new EmployeeViewModel();
    }
    private void OpenDept(object obj)
    {
        _navigationViewModel.SelectedViewModel = new DepartmentViewModel();
    }
}

MenuView.xaml.cs:

public partial class MenuView : UserControl
{
    public MenuView()
    {
        InitializeComponent();
    }
}
mm8
  • 163,881
  • 10
  • 57
  • 88
  • ok ! but, it tells me : Non-invocable member 'MenuViewModel' cannot be used like a method. – Json Feb 14 '17 at 15:51
  • Non-invocable member 'MenuViewModel' cannot be used like a method – Json Feb 14 '17 at 15:53
  • aaaahhhh yes,i should have seen it. but it doesn't work. maybe a have a problem with dataContext in one of my userControl... – Json Feb 14 '17 at 15:57
  • when i click on one of the buttons, the userControl doesn't change :/ – Json Feb 14 '17 at 15:59
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/135702/discussion-between-json-and-mm8). – Json Feb 14 '17 at 16:01
  • i tried to do the same between page 2 and page 3 (button on page 2 -> go to page 3) but apparently i didn't get it :/ – Json Feb 15 '17 at 16:16
  • Please ask a new question if you have a new issue. – mm8 Feb 15 '17 at 19:26
  • Quick question.. with this method, how can you have 2 different ViewModels? So one grid has this ViewModel and another has another ViewModel.. Because at the moment I am setting Manual DataContext within the View like so `DataContext = new BaseViewModel() { ... }` – Eduards Jan 29 '21 at 15:30