У меня это по большей части (то есть группы работают, но все группы должны иметь один и тот же уровень).
Product
Book
RecipeBook
Book#1
Book#2
ProgramingBook
Book#1
....
Disk
Disk
Disk#1
Disk#2
.....
Я использую ваши данные в качестве входных данных, поэтому моя структура классовследующим образом:
class Product
{
public string Name { get; set; }
}
class Book : Product
{
public string BookName { get; set; }
}
class RecipeBook : Book
{
public int NumRecipes { get; set; }
}
class ProgrammingBook : Book
{
public string LanguageCovered { get; set; }
}
class Disk : Product
{
public int Size { get; set; }
}
заполняется следующим образом:
ObservableCollection<Product> products = new ObservableCollection<Product>();
products.Add(new ProgrammingBook() { BookName = "P1", LanguageCovered = "C#" });
products.Add(new ProgrammingBook() { BookName = "P2", LanguageCovered = "F#" });
products.Add(new RecipeBook() { BookName = "P3", NumRecipes = 4 });
products.Add(new RecipeBook() { BookName = "P4", NumRecipes = 6 });
products.Add(new Disk() { Size = 512 });
products.Add(new Disk() { Size = 1024 });
this.DataContext = products;
Нам нужно группирование по типу, чтобы мы могли использовать конвертер в CollectionViewSource PropertyGroupDescription.
Это мойконвертер (я передаю разные значения для разных уровней иерархии для типа:
public class GroupByType : IValueConverter
{
public string type { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (type == "root")
{
if (value is Product)
{
return "Product";
}
return null;
}
if (type == "subs")
{
if (value is Book)
{
return "Book";
}
if (value is Disk)
{
return "Disk";
}
}
if (type == "main")
{
if (value is ProgrammingBook)
{
return "PBook";
}
if (value is RecipeBook)
{
return "RBook";
}
if (value is Disk)
{
return "Disk";
}
}
return null;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
, как только у нас есть данные, нам нужны соответствующие шаблоны (мои простые и показаны в конце xaml), нонам нужен какой-то способ их выбора, поэтому я использую следующий селектор шаблонов:
public class Selector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
string templateKey;
if (item is CollectionViewGroup)
{
if ((item as CollectionViewGroup).Name == null)
{
return null;
}
templateKey = "GroupTemplate";
}
else if (item is ProgrammingBook)
{
templateKey = "pTemplate";
}
else if (item is RecipeBook)
{
templateKey = "rTemplate";
}
else if (item is Disk)
{
templateKey = "dTemplate";
}
else
{
return null;
}
return (DataTemplate)((FrameworkElement)container).FindResource(templateKey);
}
}
Мой XAML выглядит так:
<Window.Resources>
<HierarchicalDataTemplate x:Key="GroupTemplate" ItemsSource="{Binding Path=Items}">
<TextBlock Text="{Binding Path=Name}" FontWeight="Bold"/>
</HierarchicalDataTemplate>
<DataTemplate x:Key="pTemplate">
<TextBlock Text="{Binding Path=LanguageCovered }"/>
</DataTemplate>
<DataTemplate x:Key="rTemplate">
<TextBlock Text="{Binding Path=NumRecipes}"/>
</DataTemplate>
<DataTemplate x:Key="dTemplate">
<TextBlock Text="{Binding Path=Size}"/>
</DataTemplate>
<c:GroupByType x:Key="gt" />
<c:Selector x:Key="s"/>
<CollectionViewSource Source="{Binding}" x:Key="cvs">
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription>
<PropertyGroupDescription.Converter>
<c:GroupByType type="root"/>
</PropertyGroupDescription.Converter>
</PropertyGroupDescription>
<PropertyGroupDescription>
<PropertyGroupDescription.Converter>
<c:GroupByType type="subs"/>
</PropertyGroupDescription.Converter>
</PropertyGroupDescription>
<PropertyGroupDescription>
<PropertyGroupDescription.Converter>
<c:GroupByType type="main"/>
</PropertyGroupDescription.Converter>
</PropertyGroupDescription>
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</Window.Resources>
<Grid>
<TreeView ItemsSource="{Binding Source={StaticResource cvs}, Path=Groups}" ItemTemplateSelector="{StaticResource s}"/>
</Grid>
Идея в том, чтодля каждого типа в вашей иерархии мы создаем новую группу с фактическими объектами, являющимися листовыми узлами дерева. Вы можете добавить столько уровней в группу, сколько вам нужно, добавив новые разделы в конвертер.n также переименуйте группы, изменив возвращаемое значение преобразователя.
Если у вас есть какие-либо вопросы, пожалуйста, задавайте, так как это довольно длинный ответ:).