Reputation: 1700
Ok, I'm trying to get to grips with MVVM. I have an application that has multiple options for image capture. Depending on the mode, the image is either loaded from an existing file, or captured from a camera.
I'm writing a page using the MVVM pattern which represents the configuration of the image capture device.
The model consists of two classes which expose the specific (and non common) values for each of the modes which conform to a common interface of IImageSource
.
Each of the two model classes have a contextually defined viewmodel:
CameraSourceViewModel
FileSourceViewModel
and two corresponding views.
CameraSourceView
FileSourceView
The model has an attribute which returns IImageSource.
I'm currently using third view, ImageSourceView
as the page. I'm handling the loading event which gets the value from the model, then, depending on the type will instantiate the correct viewmodel and the correct view to go with it and then adds that as it's content. However, this seems to be going against the spirit of MVVM in that I've now written some decision code in the code behind
Is there a more elegant/ better way of determining which viewmodel/ view should be instantiated and used?
Upvotes: 2
Views: 2707
Reputation: 62544
You have two palces where you need decide which type to use in run time:
On ViewModel level just use ViewModel factory, so just by an EventType/ValueType instantiates an appropriate ViewModel:
private IImageSourceViewModel ProcessEvent(IEvent someEvent)
{
return viewModelFactory.Create(someEvent.Type)
}
Then on View level just use DataTemplateSelector which accepts via binding already resolved ViewModel instance and then decides which View to use:
MainView XAML:
<ContentControl
Content="{Binding ImageSourceViewModel}"
ContentTemplateSelector =
"{StaticResource ImageSourceViewDataTemplateSelector}">
</ContentControl>
ImageSourceViewDataTemplateSelector:
private sealed class ImageSourceViewDataTemplateSelector: DataTemplateSelector
{
public ImageSourceViewDataTemplateSelector(... dependencies if any...)
{
}
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
DataTemplate dataTemplate = null;
IImageSourceViewModel instance = item as IImageSourceViewModel;
// move out into the constructor
var dataTemplateFactory = new Dictionary<Type, Func<DataTemplate>>
{
{ typeof(ICameraSourceViewModel), (x) => this.Resources["CameraSourceDataTemplate"] as DataTemplate },
{ typeof(IFileSourceViewModel), (x) => this.Resources["FileSourceViewModel"] as DataTemplate }
};
// TODO: handle not supported type case yourself
return dataTemplateFactory[instance.GetType()]();
}
}
Upvotes: 1
Reputation: 2944
Actually, you shouldn't need a TemplateSelector, since the two ViewModels will have different types. You can declare DataTemplates in XAML as resources with the model type as key, so that WPF chooses the correct DataTemplate automatically:
Code Example:
<Page x:Class="Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:my="clr-namespace:WpfApplication1"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
Title="Page1">
<Page.Resources>
<DataTemplate DataType="{x:Type my:CameraSourceViewModel}">
<my:CameraSourceView/>
</DataTemplate>
<DataTemplate DataType="{x:Type my:FileSourceViewModel}">
<my:FileSourceView/>
</DataTemplate>
</Page.Resources>
<Grid>
<ContentControl Content="{Binding ImageSourceViewModel}"/>
</Grid>
</Page>
Upvotes: 4
Reputation: 48995
Here's some idea about what you could do:
Have a ImageSourceViewModel
, that is the ViewModel of your ImageSourceView
view. It would be the role of this viewModel to get "your value" from the model, and expose it as a public property of type IImageSource
.
Then, in your ImageSourceView
view, you could use a template selector to change the content of the view, depending on the concrete type of the exposed IImageSource
property.
See http://www.codeproject.com/Articles/418250/WPF-Based-Dynamic-DataTemplateSelector
Upvotes: 1