WPF Treeview HierarchicalDataTemplate on Type with sub-collection
Hi Folks. I have the following two models (abridged for brevity) and mainViewModel:
and my xaml:
I'm only getting the Gist displayed and not the GistFiles on a sub-level. I know I'm getting this wrapped around my head conceptually - what am I doing wrong?
internal class Gist
{
public ObservableCollection<GistFile> GistFiles { get; set; } = new();
public override string ToString()
{
return GistFiles.OrderBy(gf => gf.Filename).First().Filename;
}
}
internal class GistFile
{
public string Filename { get; set; }
public override string ToString()
{
return Filename;
}
}
internal class MainWindowViewModel : ViewModelBase
{
private ObservableCollection<Models.Gist> gists = new ObservableCollection<Models.Gist>();
public ObservableCollection<Models.Gist> Gists { get => gists; set => SetProperty(ref gists, value); }
}
internal class Gist
{
public ObservableCollection<GistFile> GistFiles { get; set; } = new();
public override string ToString()
{
return GistFiles.OrderBy(gf => gf.Filename).First().Filename;
}
}
internal class GistFile
{
public string Filename { get; set; }
public override string ToString()
{
return Filename;
}
}
internal class MainWindowViewModel : ViewModelBase
{
private ObservableCollection<Models.Gist> gists = new ObservableCollection<Models.Gist>();
public ObservableCollection<Models.Gist> Gists { get => gists; set => SetProperty(ref gists, value); }
}
<TreeView x:Name="GistsTV" ItemsSource="{Binding Gists}" Width="200">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Gists.Files}">
<TextBlock Text="{Binding}"></TextBlock>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
<TreeView x:Name="GistsTV" ItemsSource="{Binding Gists}" Width="200">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Gists.Files}">
<TextBlock Text="{Binding}"></TextBlock>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
1 Reply
For clarity - I'm wanting Gists to display at the root level and them GistFiles to display at the child level
Bingo:
I guess WPF hooks hem all up in the background
For completness:
<DockPanel>
<DockPanel.Resources>
<HierarchicalDataTemplate DataType="{x:Type models:Gist}" ItemsSource="{Binding Path=GistFiles}">
<TextBlock Text="{Binding Id}"></TextBlock>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type models:GistFile}">
<TextBlock Text="{Binding Filename}"></TextBlock>
</DataTemplate>
</DockPanel.Resources>
<TreeView x:Name="GistsTV" ItemsSource="{Binding Gists}" Width="200">
</TreeView>
</DockPanel>
<DockPanel>
<DockPanel.Resources>
<HierarchicalDataTemplate DataType="{x:Type models:Gist}" ItemsSource="{Binding Path=GistFiles}">
<TextBlock Text="{Binding Id}"></TextBlock>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type models:GistFile}">
<TextBlock Text="{Binding Filename}"></TextBlock>
</DataTemplate>
</DockPanel.Resources>
<TreeView x:Name="GistsTV" ItemsSource="{Binding Gists}" Width="200">
</TreeView>
</DockPanel>
internal class GistFilesToFirstFilenameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
ObservableCollection<Models.GistFile> gistFiles = (ObservableCollection<Models.GistFile>) value;
if (gistFiles.Count > 0)
{
return gistFiles.First().Filename;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
internal class GistFilesToFirstFilenameConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
ObservableCollection<Models.GistFile> gistFiles = (ObservableCollection<Models.GistFile>) value;
if (gistFiles.Count > 0)
{
return gistFiles.First().Filename;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
<converters:GistFilesToFirstFilenameConverter x:Key="GistFilesToFirstFilenameConverter"/>
<DockPanel Width="Auto">
<DockPanel.Resources>
<HierarchicalDataTemplate DataType="{x:Type models:Gist}" ItemsSource="{Binding Path=GistFiles}">
<TextBlock Text="{Binding GistFiles, Converter={StaticResource GistFilesToFirstFilenameConverter}}"></TextBlock>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type models:GistFile}">
<TextBlock Text="{Binding Filename}"></TextBlock>
</DataTemplate>
</DockPanel.Resources>
<TreeView x:Name="GistsTV" ItemsSource="{Binding Gists}">
</TreeView>
</DockPanel>
<converters:GistFilesToFirstFilenameConverter x:Key="GistFilesToFirstFilenameConverter"/>
<DockPanel Width="Auto">
<DockPanel.Resources>
<HierarchicalDataTemplate DataType="{x:Type models:Gist}" ItemsSource="{Binding Path=GistFiles}">
<TextBlock Text="{Binding GistFiles, Converter={StaticResource GistFilesToFirstFilenameConverter}}"></TextBlock>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type models:GistFile}">
<TextBlock Text="{Binding Filename}"></TextBlock>
</DataTemplate>
</DockPanel.Resources>
<TreeView x:Name="GistsTV" ItemsSource="{Binding Gists}">
</TreeView>
</DockPanel>