Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVVM with complex Models

Tags:

c#

mvvm

wpf

When utilising the MVVM pattern I am coming into some trouble when the Model objects become complex, that is, when they contain Properties which are non-primitive / not built-in. In my particular instance I have a ModelA which contains a collection of ModelB objects which themselves contains a collection of ModelC objects:

class ModelA
{
    public string Name { get; set; }
    public OberservableCollection<ModelB> Bs { get; set; }
}

class ModelB
{
    public string Make { get; set; }
    public ObservableCollection<ModelC> Cs { get; set; }
}

class ModelC
{
    public string Brand{ get; set; }
}

I have a ModelAViewModel which permits access to the collection of ModelB Bs property. In this instance I have not created a ViewModel for ModelB. I have styled the ModelB and ModelC collections (and individual instances) by using DataTemplates:

<DataTemplate x:Key="modelATemplate">
    <Grid Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>
        <ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto">
            <ItemsControl  ItemsSource="{Binding Bs}" ItemTemplate="{StaticResource modelBTemplate}"/>
        </ScrollViewer>
    </Grid>
</DataTemplate>

<DataTemplate x:Key="modelBTemplate">
    <Grid Margin="5" HorizontalAlignment="Center">
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <TextBlock Grid.Row="0" Text="{Binding Make}">
        <ItemsControl Grid.Row="1" ItemsSource="{Binding Mode=OneWay, Path=Cs}"
                  ItemTemplate="{StaticResource ResourceKey=modelCTemplate}">
        </ItemsControl>
    </Grid>
</DataTemplate>

I have been advised that this is not the MVVM way of doing things and that each entity, that is, ModelB and ModelC should have their own ViewModel. I have been told to keep the Model classes but create ViewModels for them. I am unable to visualise how this is going to work.

If I create a ModelBViewModel:

public class ModelBViewModel
{
     ModelB MyModelB { get; set; }
}

I have a predicament - I already have ModelB instances within the ModelA class, I would now have other ModelB instances in the ModelBViewModel. Is it necessary to iterate through the original ModelB collection within ModelA and create the ModelBViewModels, setting the MyModelB property to match that in ModelA as I go? It seems a bit complicated for what should be rather simple?

like image 378
monster Avatar asked Nov 09 '22 03:11

monster


1 Answers

MVVM means "Model View ViewModel". As you can see, the name contains Model and ViewModel. The idea is to have a dedicated ViewModel class for every Model class you have.

The ViewModel should contain view-specific properties and logic while the Model class should contain business model specfic properties and logic.

And: Yes, for some very simple MVVM examples this might be overhead. However you benefit from this seperation as soon as your view logic starts to diverge from your business logic.

If it is necessary to iterate through the original properties: I would say: Yes! I usually do it this way:

public class ModelBViewModel
{
    private ModelB _model;

    public ObservableCollection<ModelCViewModel> CVms { get; set; }

    public ModelBViewModel(ModelB model) {
        _model = model;
        CVms = new ObservableCollection();
        foreach(var modelC in model.Cs) {
            CVms.Add(new ModelCViewModel(modelC));
        }
    }
}
like image 71
makzr Avatar answered Nov 14 '22 21:11

makzr