J'essaie d'obtenir un TreeView
pour lier ma collection afin que tous les groupes affichent des groupes imbriqués et que chaque groupe affiche l'entrée.
Comment puis-je utiliser le HierarchicalDataTemplate
pour que le TreeView
traite à la fois les sous-groupes et la collection d'entrées?
Les groupes affichent des sous-groupes et des entrées:
Example:
Group1
--Entry
--Entry
Group2
--Group4
----Group1
------Entry
------Entry
----Entry
----Entry
--Entry
--Entry
Group3
--Entry
--Entry
namespace TaskManager.Domain
{
public class Entry
{
public int Key { get; set; }
public string Name { get; set; }
}
}
namespace TaskManager.Domain
{
public class Group
{
public int Key { get; set; }
public string Name { get; set; }
public IList<Group> SubGroups { get; set; }
public IList<Entry> Entries { get; set; }
}
}
namespace DrillDownView
{
public class TestData
{
public IList<Group> Groups = new List<Group>();
public void Load()
{
Group grp1 = new Group() { Key = 1, Name = "Group 1", SubGroups = new List<Group>(), Entries = new List<Entry>() };
Group grp2 = new Group() { Key = 2, Name = "Group 2", SubGroups = new List<Group>(), Entries = new List<Entry>() };
Group grp3 = new Group() { Key = 3, Name = "Group 3", SubGroups = new List<Group>(), Entries = new List<Entry>() };
Group grp4 = new Group() { Key = 4, Name = "Group 4", SubGroups = new List<Group>(), Entries = new List<Entry>() };
//grp1
grp1.Entries.Add(new Entry() { Key=1, Name="Entry number 1" });
grp1.Entries.Add(new Entry() { Key=2, Name="Entry number 2" });
grp1.Entries.Add(new Entry() { Key=3,Name="Entry number 3" });
//grp2
grp2.Entries.Add(new Entry(){ Key=4, Name = "Entry number 4"});
grp2.Entries.Add(new Entry(){ Key=5, Name = "Entry number 5"});
grp2.Entries.Add(new Entry(){ Key=6, Name = "Entry number 6"});
//grp3
grp3.Entries.Add(new Entry(){ Key=7, Name = "Entry number 7"});
grp3.Entries.Add(new Entry(){ Key=8, Name = "Entry number 8"});
grp3.Entries.Add(new Entry(){ Key=9, Name = "Entry number 9"});
//grp4
grp4.Entries.Add(new Entry(){ Key=10, Name = "Entry number 10"});
grp4.Entries.Add(new Entry(){ Key=11, Name = "Entry number 11"});
grp4.Entries.Add(new Entry(){ Key=12, Name = "Entry number 12"});
grp4.SubGroups.Add(grp1);
grp2.SubGroups.Add(grp4);
Groups.Add(grp1);
Groups.Add(grp2);
Groups.Add(grp3);
}
}
}
<Window x:Class="DrillDownView.Window2"
xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:TaskManager.Domain;Assembly=TaskManager.Domain"
Title="Window2" Height="300" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TreeView Name="GroupView" Grid.Row="0" Grid.Column="0" ItemsSource="{Binding}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Group}" ItemsSource="{Binding SubGroups}">
<TextBlock Text="{Binding Path=Name}" />
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:Entry}" ItemsSource="{Binding Entries}">
<TextBlock Text="{Binding Path=Name}" />
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
</Grid>
</Window>
public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
LoadView();
}
private void LoadView()
{
TestData data = new TestData();
data.Load();
GroupView.ItemsSource = data.Groups;
}
}
Un HierarchicalDataTemplate
est une façon de dire 'c'est ainsi que vous rendez ce type d'objet et voici une propriété qui peut être sondée pour trouver les nœuds enfants sous cet objet'
Par conséquent, vous avez besoin d'une seule propriété qui renvoie les "enfants" de ce nœud. par exemple. (Si vous ne pouvez pas faire dériver à la fois le groupe et l'entrée d'un type Node type)
public class Group{ ....
public IList<object> Items
{
get
{
IList<object> childNodes = new List<object>();
foreach (var group in this.SubGroups)
childNodes.Add(group);
foreach (var entry in this.Entries)
childNodes.Add(entry);
return childNodes;
}
}
Ensuite, vous n'avez pas besoin d'un HierarchicalDataTemplate
pour l'entrée car une entrée n'a pas d'enfants. Le XAML doit donc être modifié pour utiliser la nouvelle propriété Items et un DataTemplate
pour Entry:
<TreeView Name="GroupView" Grid.Row="0" Grid.Column="0" ItemsSource="{Binding}">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Group}" ItemsSource="{Binding Items}">
<TextBlock Text="{Binding Path=Name}" />
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:Entry}" >
<TextBlock Text="{Binding Path=Name}" />
</DataTemplate>
</TreeView.Resources>
</TreeView>
Et voici à quoi ça ressemble.
Je pense que vous êtes la plupart du temps là-bas ... avec un tout petit peu de retouches, vous devriez faire en sorte que cela fonctionne assez facilement ...
Je vous suggère de créer une classe abstraite de base (ou une interface, selon votre préférence) et de l'hériter/l'implémenter pour la classe Group et Entry ...
De cette façon, vous pouvez exposer une propriété dans votre objet Group
public ObservableCollection<ITreeViewItem> Children { get; set; }
^ à ce stade, vous pouvez prendre une décision si cela remplace vos listes de sous-groupes et d'entrées, ou simplement les ajoute ensemble et les renvoie dans le getter de propriété ...
Maintenant, tout ce dont vous avez besoin est de remplir la collection Children avec des objets Group ou Entry, et le HierarchicalDataTemplate
s'affichera correctement lorsque les objets seront placés dans TreeView.
Une dernière pensée, si Entry est toujours le "niveau inférieur" de l'arborescence (c'est-à-dire qu'il n'a pas d'enfants), alors vous n'avez pas besoin de définir un HierarchicalDataTemplate
pour l'objet Entry, un DataTemplate
suffira .
J'espère que cela t'aides :)
Voici une implémentation alternative de la réponse de Gishu qui retourne un IEnumerable
plutôt qu'un IList
, et utilise le mot clé yield
pour simplifier le code:
public class Group
{
...
public IEnumerable<object> Items
{
get
{
foreach (var group in this.SubGroups)
yield return group;
foreach (var entry in this.Entries)
yield return entry;
}
}
}
Ce message m'a aidé lors de la recherche d'une solution pour le même problème: http://blog.pmunin.com/2012/02/xaml-binding-to-compositecollection.html
en utilisant MultiBinding et CompositeCollectionConverter ..
/ Cordialement Anders