I'd like to create a flexible application which is ViewModel driven.
The basic flow is like this:
If a sub view model needs to be presented, it is done via a DataTemplate.
This approach can also be seen here (option 8).
So the main window xaml looks something like this:
<Window>
<!-- somehow I need to add the mapping from ViewModel to View -->
<Grid>
<!-- the main ViewModel -->
<ContentPresenter Content="{Binding Path=Content}"/>
</Grid>
</Window>
The Content
property might contain a view model that contains a list of elements named Children
and it's associated DataTemplate might look like this:
The children are also flexibly rendered by a suitable DataTemplate.
<UserControl>
<Grid>
<StackPanel>
<!-- display the child ViewModels in a list -->
<ItemsControl ItemsSource="{Binding Path=Children}" />
</StackPanel>
</Grid>
</UserControl>
How should I organize the ViewModels, Views and their DataTemplates so I don't need to hardwire them in the MainWindow?
How do I then connect this to the main window?
It would be nice if it is stub-able, i.e. I can see the result during design time with a design time dataContext.
Basically I want to bundle the View, ViewModel and DataTemplate and be able to use them in an application that doesn't need to know about the details (e.g. some sub ViewModel implements a certain interface and is injected into the main ViewModel).
Have you looked into Prism.
The framework allows you to define regions within your UI that views can be registered against. I believe this answers your 2nd question (2).
xmlns:cal="http://www.codeplex.com/prism"
<Window>
<!-- somehow I need to add the mapping from ViewModel to View -->
<Grid>
<!-- the main ViewModel -->
<ContentPresenter cal:RegionManager.RegionName="MainRegion"/>
</Grid>
</Window>
For your first question (1) we structure our entities in the following way:
View - we have an abstract base class that looks similar too:
public abstract class ViewBase<T> : UserControl, IView<T> where T: IViewModel
{
public T ViewModel
{
get
{
return this.viewModel;
}
protected set
{
this.viewModel = value;
this.DataContext = this.viewModel;
}
}
public ViewBase(IUnityContainer container)
{
this.ViewModel = container.Resolve<T>();
}
}
This then allows us to create Views in xaml using the following:
<ui:ViewBase x:Class="MyView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:ui="NAMESPACE FOR VIEWBASE"
xmlns:vm="NAMESPACE FOR VIEWMODEL"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:TypeArguments="vm:MYVIEWMODEL">
In the code behind of a View we do the following:
public partial class MyView : ViewBase<IMyViewModel>
This then makes use of the constructor in the base class to resolve the ViewModel and set it to it's DataContext.
This then allows you to design your view (3) as you intended and also removes the need for having a DataTemplate.
Using the UnityContainer we then register the views as follows:
this.container.RegisterType<IMyView, MyView>();
this.container.RegisterType<IMyViewModel, MyViewModel>();
this.regionManager.RegisterViewWithRegion("MainRegion", typeof(IMyView));
Note that "MainRegion" here matches the RegionName specified in the MainWindow xaml. You can expand this further to use a TabControl if you wanted to display multiple views in the same area, or even break your MainWindow down into different regions.
I hope this helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With