In the MVVM pattern, the view shouldn't know anything about the models, but what if I wanna display different types differently?
For example I have two classes. The class Message and the class AttachmentMessage which inherits from Message.
Message
public class Message
{
public string Content { get; set; }
}
AttachmentMessage
public class AttachmentMessage : Message
{
public string Filename { get; set; }
}
Now when I use them in an ObservableCollection<Message>
, I have both models in this collection, but I can't tell WPF which Datatemplate it has to use, without knowing which Models there are.
So what are solutions for this problem?
CodePudding user response:
The most common and recommended way would be to create a data template for each type you need and put that in your resources.
The following code assumes your observable collection has the name Messages
.
Example:
<ItemsControl ItemsSource="{Binding Messages}">
<ItemsControl.Resources>
<DataTemplate DataType="{x:Type local:Message}">
<TextBlock Text="{Binding Content}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:AttachmentMessage}">
<TextBlock Text="{Binding Filename}"/>
</DataTemplate>
</ItemsControl.Resources>
</ItemsControl>
The other way is to create a DataTemplateSelector
. Let's say your messages all had a property that indicated their priority. You could create a template selector like the below. DataTemplateSelector
can be used when you need more fine-grained control over which template is selected.
public class MyDataTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is Message m && container is FrameworkElement fm)
{
if (m.Priority == Priority.High)
{
return fm.FindResource("HighPriorityTemplate") as DataTemplate;
}
else
{
return fm.FindResource("NormalPriorityTemplate") as DataTemplate;
}
}
return null;
}
}
And use it in xaml like the following:
<Window.Resources>
<!-- Put your templates here-->
<local:MyDataTemplateSelector x:Key="MyDataTemplateSelector"/>
</Window.Resources>
<ItemsControl ItemsSource="{Binding Messages}" ItemTemplateSelector="{StaticResource MyDataTemplateSelector}">
As I side note, in the MVVM pattern, usually you have three parts, Model
, View
and ViewModel
. Some people take the shortcut of binding directly to the Model
, but I generally would avoid this. You can find a discussion about this here.