tete
tete

Reputation: 5019

Open new View when new ViewModel is available?

I am relatively new to WPF/MVVM. Our current WPF project is still a prototype application, which means we haven't come to designing of main layout. But we do have designed some reports (by reports, I mean some quite complicated UserControl each of which has some configuration controls such as ComobBoxor TextBox, and some DataGrid, Graph controls for the data we want to present) as Viewand their ViewModel. It is still prototype, so we just need to open a new Window which displays any of these UserControl. In the future, we might change it to locate different UserControl in different regions inside the main window, like the layout of Visual Studio. The MAIN point is, our application would include almost a hundred of such UserControl or what we call reports. So it is different from my previous working projects which had static layout/MainView.

I still haven't figured out a good architecture for it. Our classic usage scenario is to let the user to select in the menu report to open, and so we have Command (either in MainViewModel, or in any ViewModel of report) objects to open a new report. So basically the Command is generating a new ViewModel (ViewModel first case) and then a corresponding View should be generated (by whom?), and finally a new Window should be opened including the newly-generated UserControl.

I guess I need two services:

  1. a service which subscribes to the new-ViewModel-generated event, and resolve the UserControl when such event happens.

  2. (for our current prototype application) a window manager, which subscribes to the new-UserControl-generated event published by the 1) service, and then opens a new Window to display it.

And in the future for our actual application, we can change the 2) service and put them into different regions. For the second, it is simple and only temporary, I can just have one object in the code-behind of MainView, which subscribes to the event using EventAggregator, and generate a new Window. Is it correct ?

Can somebody tell me how I should achieve this?

Upvotes: 0

Views: 86

Answers (2)

hschne
hschne

Reputation: 704

John Bowen beat me to it, by I thought I'd still post, maybe it helps.

For associating views with view models you can use data templates in a resource dictionary.

<DataTemplate DataType="{x:Type vm:AllCustomersViewModel}">
    <vw:AllCustomersView />
</DataTemplate>

As you probably already know, you can set namespaces within your resource dictionaries. In this example vw and vm reference the folders containing viewmodels and views respectively. Now you can use content control to generate the views by binding to the view model.

<ContentControl Content="{Binding SomeViewModel}" />

The code above has been shamelessly stolen from Josh Smith btw.

So, you should not need a service for resolving the association of view to viewmodel. Let the framework do the work for you. I actually do not recommend opening new windows. If you must, using a "Window Controller"-Service of some sort will be unavoidable. However, I advise you to stick to a single window containing multiple viewmodels and exchanging them upon receiving certain events.

Upvotes: 0

John Bowen
John Bowen

Reputation: 24453

Data binding can already handle this for you. In the container where you want to display the reports add a ContentControl and bind it to a property that holds the VM for the report that you want to display currently.

<Window>
  <ContentControl Content="{Binding Path=CurrentReport}" />
</Window>

To display the different reports wrap each of the UserControls in its own DataTemplate that can be injected into the ContentControl. To actually resolve the view you have a few choices. You can create a DataTemplateSelector to map them or just specify the VM types on your templates. In either case, make sure the templates are in scope at the ContentControl (in Resources in the same file or a parent, or merged from standalone ResourceDictionary).

<DataTemplate DataType="{x:Type viewModels:FirstReportViewModel}">
  <views:FirstReportViewControl/>
</DataTemplate>

Upvotes: 2

Related Questions