Reputation: 4401
Let's imagine that I have :
namespace Project.Common
{
public enum FileTypeEnum
{
Text = 1,
Image = 2,
Audio = 3,
Video = 4
}
public class Artifact
{
public long? ArtifactId { get; set; }
public FileTypeEnum FileType { get; set; }
public string Path { get; set; }
public string Text { get; set; }
}
}
Above is an enum for all the file types that could be. Also, an Artifact
model. Below is an observable collection called Artifacts
such as :
public ObservableCollection<Grouping<FileTypeEnum, Artifact>> Artifacts {get; set;}
Now, When the page loads, with dummy data I populate the list as.
var list = new List<Artifact>();
list.Add(new Artifact() { ArtifactId = 1, FileType = FileTypeEnum.Image, Path = String.Format(@"\img.png") });
list.Add(new Artifact() { ArtifactId = 2, FileType = FileTypeEnum.Audio, Path = String.Format(@"\aud.mp3") });
list.Add(new Artifact() { ArtifactId = 3, FileType = FileTypeEnum.Text, Path = "", Text = "Lorem Ipsum .." });
list.Add(new Artifact() { ArtifactId = 4, FileType = FileTypeEnum.Image, Path = String.Format(@"img.png") });
list.Add(new Artifact() { ArtifactId = 5, FileType = FileTypeEnum.Video, Path = String.Format(@"vid.mp4") });
list.Add(new Artifact() { ArtifactId = 6, FileType = FileTypeEnum.Image,, Path = String.Format(@"img.png") });
Objective is to show the observable collection in the view as grouped data, with all images under image block, audio under audio block and so on..
What I've tried so for --
I use the following class to group the list based on same file type:
public class Grouping<T1, T2>
{
private FileTypeEnum key;
private IGrouping<FileTypeEnum, Artifact> group;
public Grouping(FileTypeEnum key, IGrouping<FileTypeEnum, Artifact> group)
{
this.key = key;
this.group = group;
}
}
so that the observable collection is as
var grouped = from m in list
group m by m.FileType into Group
select new Grouping<FileTypeEnum, Artifact>(Group.Key, Group);
this.Artifacts = new ObservableCollection<Grouping<FileTypeEnum, Artifact>>(grouped);
This returns all artifacts grouped together based on the key which is the file type. The problem is the xaml
view which I am not able to render properly(as I don't know how). The so far xaml
view as below :
<ItemsControl ItemsSource="{Binding Artifacts}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<Label Content="{Binding key}" />
<ItemsControl ItemsSource="{Binding}" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Path}"/>
</DataTemplate >
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
My understanding is to have different <DataTemplate>
for each file type so I can show all images under 'image' heading and together, similarly, all audio blocks under an Audio
heading. Any alternatives to my approach are most welcomed.
Upvotes: 1
Views: 1692
Reputation: 169160
Bind to the ungrouped collection of Artifacts
:
public ObservableCollection<Artifact> Artifacts {get; set;}
...
this.Artifacts = new ObservableCollection<Artifact>(list);
...and perform the grouping in the view using a CollectionViewSource
and a GroupStyle
:
<Window.Resources>
<CollectionViewSource x:Key="cvs" Source="{Binding Artifacts}">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="FileType" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
...
<ItemsControl ItemsSource="{Binding Source={StaticResource cvs}}">
<ItemsControl.GroupStyle>
<GroupStyle>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" IsItemsHost="True"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Label Content="{Binding Name}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ItemsControl.GroupStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Path}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Awesome! Can you please tell how I can add more data template for other file types, for ex TextBlock for Text file type which would bind to Text property and not Path
You could use a DataTemplateSelector or a ContentControl
with data triggers:
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Style.Triggers>
<DataTrigger Binding="{Binding FileType}" Value="Image">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Image Source="{Binding Path}"/>
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
<DataTrigger Binding="{Binding FileType}" Value="Text">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<TextBlock Text="{Binding Text}" />
</DataTemplate>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</DataTemplate>
</ItemsControl.ItemTemplate>
Upvotes: 2
Reputation: 683
Make key and group in your Grouping class public. Also bind the Itemssource to group.
Upvotes: 0