Here is a complete solution whereby a hierarchical data source is flattened and bound to a listbox:
Step 1: Add this extension class.
using System.Collections.Generic;
using System;
namespace HierarchicalData.Extensions
{
public static class IEnumerableExtensions
{
public static IEnumerable<T> Flatten<T>(this IEnumerable<T> rootLevel, Func<T, IEnumerable<T>> nextLevel)
{
List<T> accumulation = new List<T>();
accumulation.AddRange(rootLevel);
flattenLevel<T>(accumulation, rootLevel, nextLevel);
return accumulation;
}
private static void flattenLevel<T>(List<T> accumulation, IEnumerable<T> currentLevel, Func<T, IEnumerable<T>> nextLevel)
{
foreach (T item in currentLevel)
{
accumulation.AddRange(currentLevel);
flattenLevel<T>(accumulation, nextLevel(item), nextLevel);
}
}
}
}
Step 2: The XAML. (The Listbox could be bound differently if you want)
<Window x:Class="HierarchicalData.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="600"
Width="640">
<StackPanel x:Name="LayoutRoot" Background="White">
<StackPanel.Resources>
<HierarchicalDataTemplate x:Key="ChildTemplate">
<TextBlock FontStyle="Italic" Text="{Binding Path=Field1}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="NameTemplate"
ItemsSource="{Binding Path=subitems}"
ItemTemplate="{StaticResource ChildTemplate}">
<TextBlock Text="{Binding Path=Field1}" FontWeight="Bold" />
</HierarchicalDataTemplate>
</StackPanel.Resources>
<StackPanel Orientation="Vertical">
<TreeView Width="400"
Height="300"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource NameTemplate}"
x:Name="myTreeView"/>
<ListBox Width="400"
Height="300"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource NameTemplate}"
x:Name="myListBox"/>
</StackPanel>
</StackPanel>
</Window>
Step 3: The class. Note the line which has ".Flatten" - that's the bit that does the magic. (In this case code behind for simplicity)
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using HierarchicalData.Extensions;
namespace HierarchicalData
{
public partial class MainWindow : Window
{
static public ObservableCollection<item> Topics = new ObservableCollection<item>();
static public List<item> FlatTopics = new List<item>();
public MainWindow()
{
InitializeComponent();
Topics.Add(new item("Orange", "Fruit"));
Topics.Add(new item("Banana", "Fruit"));
item DataGridTopic = new item("Gift Set", "Toiletries");
DataGridTopic.subitems.Add(new item("Shampoo", "Toiletries"));
DataGridTopic.subitems.Add(new item("Bath Bomb", "Toiletries"));
DataGridTopic.subitems.Add(new item("Scented Candle", "Household"));
Topics.Add(DataGridTopic);
myTreeView.DataContext = Topics;
myListBox.DataContext = Topics.Flatten(n => n.subitems).Distinct().ToList();
}
}
public class item
{
public string Field1 { get; set; }
public string Field2 { get; set; }
private ObservableCollection<item> subitemsValue = new ObservableCollection<item>();
public ObservableCollection<item> subitems
{
get
{
return subitemsValue;
}
set
{
subitemsValue = value;
}
}
public item() { }
public item(string field1, string field2)
{
Field1 = field1;
Field2 = field2;
}
}
}
Hopefully that's what you're after. Please mark as answer if it helps.
Sources: