Design – Multi-screen MVVM architecture/design – Should the “screen” ViewModels contain sub-ViewModels

Architecturedesignmvvm

I'm getting beyond a simple MVVM program now, and I'd just like to sense check my current architecture and makes sure I'm going down the right path here.

Everything is structured around screens, and these screens have a kind of "tree" breakdown. On the top level there's a home screen, and you can drill down through related screens.

I've made a simplified example, an application that tracks employees for companies. It has three "screens".

  • CompanyOverviewScreen, lets you see all the companies you have. Click to go to the below:
  • EmployeeTrackerScreen, lets you see all the employees in this company and their location. Click to go to the below:
  • EmployeeScreen, let's you see information about an employee.

So the screens open up like a tree:

enter image description here

Question 1: Where should these screen view models be created and stored? Should they be created and stored in one place above everything, or should the EmployeeTrackerScreen ViewModel create the EmployeeScreen ViewModel and store it as a collection property?

I'm also using shared ViewModels that don't have views for the data and UI properties in these screens where they are displaying a collection of items. For example, the EmployeeTrackerScreenView has an ItemsCollection to directly bind to an ObservableCollection that are stored as properties in the EmployeeTrackerScreenViewModel.

Here's a quick sketch of how it's structured:

enter image description here
So the EmployeeTrackerScreenView looks like this:

<UserControl x:Class="Project.EmployeeTrackerScreenView >
    <DockPanel>
        <StackPanel DockPanel.Dock="Top">
            <Label Content="{Binding CorporationViweModel.Name}" />
            <Label Content=" has " />
            <Label Content="{Binding CorporationViweModel.NumberOfEmployees}" />
        </StackPanel>
        <ScrollViewer>
            <ItemsControl ItemsSource="{Binding ObsvCollectionOfEmployeeViewModels}" >
                <ItemsControl.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Label Content="{Binding EmployeeModel.Name}"/>
                            <Label Content="is"/>
                            <Label Content="{Binding EmployeeModel.Location}"/>
                        </StackPanel>
                    </DataTemplate>
                </ItemsControl.ItemTemplate>
            </ItemsControl>
        </ScrollViewer>
    </DockPanel>
</UserControl>

Question 2 Is in line with MVVM patterns? Am I going about it the right way?

I'd love some comments on how I'm structuring things, perhaps some advice on whether I'm going about it in a sensible way. I hope the question provides enough information and is appropriate. I'm new to this kind of software design, I've always made smaller apps in the past, so I'm inexperienced in proper architecture.

I've been using Caliburn Micro MVVM framework, in WPF if that's useful to know.

Best Answer

Normally I have one overarching ApplicationViewModel that takes care of initializing ViewModels for separate screens, like this, however because of the nature of your application, it sounds like your CompanyOverviewScreenViewModel should work fine for this purpose.

Typically I would have is my main application initialize the top-level data context, and each ViewModel from there is in charge of creating/maintaining viewmodels below it.

For example :

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        var mainApp = new CompanyOverviewWindow();
        var appData = new CompanyOverviewScreenViewModel();
        mainApp.DataContext = appData;
        mainApp.Show();
    }
}

The CompanyOverviewScreenViewModel would contain a collection of CompanyModel objects, and upon selection each CompanyModel object would be displayed to the user in some kind of ContentControl or UserControl. Each CompanyModel would further have a collection of EmployeeModel objects that could also be selected and displayed.

Keep in mind that a ViewModel is really just a model of the View. For example, it sounds like you only want to display Employee objects, so using the EmployeeModel directly is perfectly acceptable. But if you wanted to provide the ability to update the EmployeeModel and include items like Save, Cancel, Delete, etc you would probably want a ViewModel to contain the extra code that is unrelated to the Employee data object itself.

In that same vein, because you want to do things like track the Selected Employee of each CompanyModel, something not normally part of the Company data object, it might make sense to use a CompanyViewModel object at that layer too. Sometimes for something as simple as just tracking selection though, I'll just add it the object model. It really depends on how big or how structured the application is.

Overall what you have now looks like you're going in the right direction, although I did have some concern about your image where it says "Each screen creates ViewModels.." in the top left corner. I typically do not advocate for a view-first approach to MVVM and WPF, and would recommend a ViewModel-first approach instead, as I described here.

Related Topic