4

I'm writing a small application whilst learning MVVM in WPF.

As long as I keep on using one Window, everything is pretty easy. Now I want to open a new Window with a specific ViewModel.

I have a main ViewModel, which contains a Command that should open a new Window / ViewModel, along with a Parameter.

my main window

To do this in an MVVM way, I've created a NavigationService, which I'd like to call like this:

    public MainWindowViewModel()
    {
        DetailsCommand = new DelegateCommand(Details);
    }

    public void Details()
    {
        SessionsViewModel sessions = new SessionsViewModel();
        _NavigationService.CreateWindow(sessions);
    }

I've noticed that it's possible to "bind" Views and ViewModels in XAML, like this:

<Application x:Class="TimeTracker.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:local="clr-namespace:TimeTracker"
             xmlns:vm="clr-namespace:TimeTracker.ViewModels"
             xmlns:vw="clr-namespace:TimeTracker.Views"
             StartupUri="Views/MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>
            <DataTemplate DataType="{x:Type vm:MainWindowViewModel}">
                <vw:MainWindow />
            </DataTemplate>
            <DataTemplate DataType="{x:Type vm:SessionsViewModel}">
                <vw:Sessions />
            </DataTemplate>
        </ResourceDictionary>
    </Application.Resources>
</Application>

<Window x:Class="TimeTracker.Views.Sessions"
        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:TimeTracker.Views"
        xmlns:vm="clr-namespace:TimeTracker.ViewModels"
        mc:Ignorable="d"
        Title="Sessions" Height="300" Width="300">
    <Window.DataContext>
        <vm:SessionsViewModel/>
    </Window.DataContext>
    <Grid>
        <TextBlock Text="Hallo" />
    </Grid>
</Window>

The problem I'm having is that I don't know how I can use this ResourceDictionary in my NavigationService, so that I can create a new Window by only using its ViewModel.

class NavigationService
{
    public void CreateWindow(IViewModel viewModel)
    {
        //How do I create a new Window using the ResourceDictionary?
    }
}
Benjamin Diele
  • 1,177
  • 1
  • 10
  • 26

1 Answers1

1

Make sure you have a ContentControl or ContentPresenter in your new window so that the ViewModel can be presented. Next, make sure that resource dictionary is in scope. Putting it in Application.Resources will make it global and guarantee that WPF can find the DataTemplate.

Also, don't use a Window class as your view in the DataTemplate. Use your sub-window panel (e.g., Grid, StackPanel, etc).

I do this:

<blah:MyChildWindow>
     <ContentControl Content={Binding DataContext}/>
</blah:MyChildWindow>

And in Application.Resources:

<DataTemplate DataType={x:Type blah:MyViewModel}>
     <blah:MyChildWindow/>
</DataTemplate>

BTW - using DataTemplates the way you are trying to do is an excellent pattern.

hoodaticus
  • 3,772
  • 1
  • 18
  • 28
  • Thanks for your answer. I've updated my XAML binding to show that it's global. Can you explain why you only have a ContentControl in your `MyChildWindow`? I'm trying to put some content in the View, like a Grid or List. Please see my Updated View. – Benjamin Diele Jan 07 '16 at 20:48
  • With the pattern you are using, the view content is supplied by the DataTemplate itself (or the UserControl / custom control you referenced in it). I suggest ContentControl because it applies whatever DataTemplate WPF can find to its content ViewModel. If you have a list of items rather than a single item, you can go with an ItemsControl like ListBox - it too will apply whatever DataTemplate it can find for each item in the list. – hoodaticus Jan 07 '16 at 21:15