MVVM pattern lets you have several ViewModels
for a single View
. Usually it refers to the View
, which can have multiple actions / states. Switching between ViewModels
can be "manually" or by using different patterns, for example by using Strategy.
Below I will discuss both principles.
Using the strategy pattern
This pattern allows you to have a set of classes that implement algorithms for a specific strategy. A simple example: you need to get from home to work (place of study, etc.). This can be done in several ways:
- Go on foot
- Ride a bike
- Travel by car / bus
All of this can be attributed to a single strategy, which includes several ways to solve a specific task. Allow a quote from the book "Gang of Four" on the applicability of the strategy pattern:
Use the Strategy pattern when:
many related classes differ only in their behavior. Strategies provide a way to configure a class with one of many behaviors.
you need different variants of an algorithm. For example, you might define algorithms reflecting different space/time trade-offs. Strategies can be used when these variants are implemented as a class hierarchy of algorithms.
an algorithm uses data that clients shouldn't know about. Use the Strategy pattern to avoid exposing complex, algorithm-specific data structures.
a class defines many behaviors, and these appear as multiple conditional statements in its operations. Instead of many conditionals, move related conditional branches into their own Strategy
class.
Structure diagram:

Conclusion for Strategy pattern
If you are using multiple operations (C
reate R
emove U
pdate D
elete) for different types, for example: add an image, add user information, add the file, which can also have subtypes, then I think the strategy is suitable for you.
Using several ViewModels for one View
As I mentioned above, MVVM pattern allows several ViewModels
for one View
. In my opinion, this is best done using a DataTemplate
, and selector DataTemplateSelector
, which will return the required template by its condition. DataTemplate
ideal for visual presenation of ViewModel
. Personally, I use dynamic DataTemplateSelector
, example:
<ContentControl Name="DynamicContentRightPanel"
Style="{StaticResource ContentControlRightPanelStyle}"
Content="{Binding Path=ContentRightPanelModel.ContentType,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}" />
In the panel may have different content, which depends on the user selection.
ContentControlRightPanelStyle
<Style x:Key="ContentControlRightPanelStyle" TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplateSelector" Value="{StaticResource MyTemplateSelector}" />
<Setter Property="DataTemplateSelectors:DynamicTemplateSelector.Templates">
<Setter.Value>
<DataTemplateSelectors:TemplateCollection>
<DataTemplateSelectors:Template Value="DateCalculator"
DataTemplate="{StaticResource DateCalcTemplate}" />
<DataTemplateSelectors:Template Value="Test"
DataTemplate="{StaticResource TestTemplate}" />
</DataTemplateSelectors:TemplateCollection>
</Setter.Value>
</Setter>
</Style>
DynamicTemplateSelector (taken and little reworked from CodeProject)
public class DynamicTemplateSelector : DataTemplateSelector
{
#region Templates Dependency Property
public static readonly DependencyProperty TemplatesProperty =
DependencyProperty.RegisterAttached("Templates", typeof(TemplateCollection), typeof(DataTemplateSelector),
new FrameworkPropertyMetadata(new TemplateCollection(), FrameworkPropertyMetadataOptions.Inherits));
public static TemplateCollection GetTemplates(UIElement element)
{
return (TemplateCollection)element.GetValue(TemplatesProperty);
}
public static void SetTemplates(UIElement element, TemplateCollection collection)
{
element.SetValue(TemplatesProperty, collection);
}
#endregion
#region SelectTemplate
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
string myStringItem = (string)item;
if (!(container is UIElement))
{
return base.SelectTemplate(item, container);
}
TemplateCollection templates = GetTemplates(container as UIElement);
if (templates == null || templates.Count == 0)
{
base.SelectTemplate(item, container);
}
foreach (var template in templates)
{
if (myStringItem.Equals(template.Value.ToString()))
{
return template.DataTemplate;
}
}
return base.SelectTemplate(item, container);
}
#endregion
}
#region TemplateCollection
public class TemplateCollection : List<Template>
{
}
#endregion
#region Template Dependency Object
public class Template : DependencyObject
{
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(string), typeof(Template));
public static readonly DependencyProperty DataTemplateProperty =
DependencyProperty.Register("DataTemplate", typeof(DataTemplate), typeof(Template));
public string Value
{ get { return (string)GetValue(ValueProperty); } set { SetValue(ValueProperty, value); } }
public DataTemplate DataTemplate
{ get { return (DataTemplate)GetValue(DataTemplateProperty); } set { SetValue(DataTemplateProperty, value); } }
}
#endregion
Conclusion for several ViewModels / one main View
If the user's choice is limited to one type of operation, which may be several, you can simply create for each ViewModel / View
(in the case of the DataTemplate), since it will be easier and more convenient.