4
votes

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?
    }
}
1

1 Answers

1
votes

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.