I created the following model (the code is simplified to illustrate the situation):
public abstract class Account { public string Name { get; set; } } public class Person : Account { public string FirstName { get; set; } public string LastName { get; set; } } public class Company : Account { public string Owner { get; set; } }
Next, I created a view model:
public class ViewModel { public Account Model { ... } public string Name { ... } public string FirstName { ... } public string LastName { ... } public string Owner { ... } ... }
And finally, the view:
<UserControl> <UserControl.Resources> <DataTemplate x:Key="personTemplate" DataType="{x:Type model:Person}"> <Grid DataContext="{Binding ElementName=rootLayout, Path=DataContext}"> <TextBlock Text="{Binding Path=Name}" /> <TextBlock Text="{Binding Path=FirstName}" /> <TextBlock Text="{Binding Path=LastName}" /> </Grid> </DataTemplate> <DataTemplate x:Key="companyTemplate" DataType="{x:Type model:Company}"> <Grid DataContext="{Binding ElementName=rootLayout, Path=DataContext}"> <TextBlock Text="{Binding Path=Name}" /> <TextBlock Text="{Binding Path=Owner}" /> </Grid> </DataTemplate> <local:AccountTemplateSelector x:Key="templateSelector" PersonTemplate="{StaticResource personTemplate}" CompanyTemplate="{StaticResource companyTemplate}" /> </UserControl.Resources> <StackPanel Name="rootLayout" DataContext="{Binding Path=viewModel}"> <ContentControl Content="{Binding Path=Model}" ContentTemplateSelector="{StaticResource templateSelector}"/> <Button Content="Save" /> <Button Content="Close" /> </StackPanel> </UserControl>
So, when the loaded model is of type Person , personTemplate displayed; on the contrary, when the Company model is shown companyTemplate .
My questions:
- Does this approach make sense at all? It would be more reasonable to remove the
Model property in the ViewModel class and introduce an enumeration or just a simple bool that would show the person if true , or the company if `false? - When defining data templates, I pointed
DataType to Person and Company (it was natural for me to do this). Do I need this at all, because in the very next line I am setting a new data context as one of UserControl ? - If
DataType data templates are different view models, something like PersonViewModel and CompanyViewModel ? Does it make sense to create them? - How can I and generally can make a data template inherit a data context from
ContentControl automatically?
I know that it all depends on personal choices at the end, but since I'm studying MVVM (I use MVVM Light), I wonder which approach would be most recommended? I still do not quite understand when classes from models should be used as data types for data templates and when models should be used for this purpose. If the assembly representing the model is even mentioned in the view assembly (assuming that the view model, model, and view are all in separate assemblies)?
Thanks for all the clarifications!
UPDATE:
This update should explain the problem of having model classes as DataType in data templates when the property of the model class is not directly tied to a single control in the view.
Person has an enumeration and a new property, so now it looks like this:
public class Person : Account { public enum GenderType { Female, Male, NotSpecified } public string FirstName { get; set; } public string LastName { get; set; } public GenderType Gender {get; set; } }
And in the view, naturally, the human data template also changes:
<DataTemplate x:Key="personTemplate" DataType="{x:Type model:Person}"> <Grid DataContext="{Binding ElementName=rootLayout, Path=DataContext}"> <TextBlock Text="{Binding Path=Name}" /> <TextBlock Text="{Binding Path=FirstName}" /> <TextBlock Text="{Binding Path=LastName}" /> <RadioButton Name="Female" /> <RadioButton Name="Male" /> <RadioButton Name="NotSpecified" /> </Grid> </DataTemplate>
If the Content parameter for ContentControl set to Model ViewModel property, how to resolve the situation with the floor / switches; because now they do not correspond to one control / one property?