Reputation: 5019
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 ComobBox
or TextBox
, and some DataGrid
, Graph
controls for the data we want to present) as View
and 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:
a service which subscribes to the new-ViewModel-generated event, and resolve the UserControl
when such event happens.
(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
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
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