3

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.

2

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.

  • Thanks for the detailed response. Lots to think about. Regarding the "Each Screen creates ViewModels", that's probably misleading. I'm using a ViewModel-first approach, I've just been calling the major ViewModels screens - which is kind of misleading. I mean the Screen ViewModel creates and stores any sub-screen ViewModels. I'll modify the wording. – Joe Mar 17 '16 at 12:34
1

Regarding the first question:

I would suggest to encapsulate your view model's creation process from the screen. You can introduce the class that will use models to create related view model.

class EmployeeTrackerScreenViewModelCollector {
  func addEmployeeModels(models: [EmployeeTrackerScreenModel])
  func collectViewModels() -> [EmployeeTrackerScreenViewModel]
}

This class can collect/sort/filter and provide ready-to-show array with view models.

About where to store viewModels, I don't see any problem to store what you show in your screen. Or if you have separate dataSource class for your screen you can store viewModels array there.
1

I can only share some thoughts about the conceptual design of your problem. I will leave the code to use as I am not familiar with the frameworks.

An important note first; the ViewModel, as others have said, is the model of a view. This, consequently, means that you can have one viewmodel per view. Now, don't confuse views with screens or forms. In a screen or a form or a window, you can have several view. For example, say that in one of your employee screens you have a kind of dashboard with a chart about the taxes or insurance they pay and a list with the benefits they receive. The chart and the list are two different "views" which means that you need two viewmodels to prepare the dataset(s) for the two views.

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?

In order to figure this out, you need to consider who is responsible to show the Tracker Screen window/dialog? There is a kind of debate in the MVVM community regarding the question you are asking. I am going to take a pragmatic approach here. If your View and the ViewModel are short-lived (like in the EmployeeScreen View in your figures) you can create the ViewModel at the same place you create and show the actual window (the View). If you are talking about an application-wide viewmodel (something you need all the time) then you can do what Rachel says. Again, you can get different approaches on this.

Another approach for the application-wide models and viewmodels would be to have a factory that generates the instances of the classes and a service locator before even you show the main window of your app. There is, also, controversy whether the service locator should be favored or not. On this, I suggest you do your own reading and see which arguments suit you.

  • I went with a factory in the end, and used a dependency injection framework/service locator. Almost all ViewModels were created from factories, with dependencies injected using the container (essentially a service locator). – Joe May 10 '17 at 10:58
-4

I am not familiar with Caliburn Micro MVVM framework, If you are open to another framework, I will advice you to use PRISM from microsoft (https://msdn.microsoft.com/en-us/library/gg406140.aspx). With PRISM you can easily display and manage your views(Screen).

  • 1
    This does not answer the question as asked. – user22815 Mar 11 '16 at 18:29
  • This answer could be improved by making a stronger case for replacing the MVVM framework and explaining why PRISM would be worth the effort. – user22815 Mar 11 '16 at 19:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.