Treeview WPF, DataBindings et HierarchicalDataTemplate

Voila, donc, je debute en WPF, apres un gros BG Winforms durant 5ans, et le moins qu’on puisse dire, c’est que ca fait bizarre. Autant le peu d’infos sur le net, autant les soucis recurents sur les memes trucs et les samples qui font jamais ce qu’on veux, je dois admettre que je galere pas mal.

Le souci du jour, c’est une Treeview qui veut pas afficher mes données comme je veux. Je suis sur que c’est tout con, et j’arrive a faire 2-3 trucs comme il faut dans un bac a sable, mais en vrai, ca se complique. (Attention, ca va etre long)

Contexte: Je veux reproduire un espece de Solution Explorer pour l’editeur de jeu que je suis en train de faire.
Données: un ensemble tout bidon de classe comme suis : je code crado la pour l’exemple, tout public et tout hein.

public class GameSolution 
{
    public List<GameLevel> Levels { get; set; }
    public List<GameEntity> Entities { get; set; }
}

public class GameLevel
{
    public List<GameEntity> Entities { get; set; }
}

public class GameEntity
{
    public List<GameAsset> Assets { get; set; }
}

public class GameAsset
{
    public List<GameEntity> Entities { get; set; }
    public List<GameAsset> Assets { get; set; }
}

Donc ca, c’est rempli aleatoirement a grand coup de random, pas de soucis de ce coté la, j’ai mes données.
Je les set sur le m_treeview avec un « m_treeview.DataContext = new GameSolution(); » et ca va la ou il faut (apparement, mais jme trompte peut etre)
Le souci arrive quand je dois afficher tout ca dans un unique arbre en WPF, via une bete TreeView.

Exemple des morceaux de XAML que j’ai testé, avec leurs resultats en dessous :

 <Grid Name="m_grid">
        <Grid.Resources>
            <HierarchicalDataTemplate x:Key="AssetTemplate">
                <TextBlock Text="{Binding Path=Name}" />
            </HierarchicalDataTemplate>
            
            <HierarchicalDataTemplate x:Key="EntityTemplate" ItemsSource="{Binding Path=Assets}" ItemTemplate="{StaticResource AssetTemplate}">
                <TextBlock Text="{Binding Path=Name}" />
            </HierarchicalDataTemplate>

            <HierarchicalDataTemplate x:Key="LevelTemplate" ItemsSource="{Binding Path=Entities}" ItemTemplate="{StaticResource EntityTemplate}">
                <TextBlock Text="{Binding Path=Name}" />
            </HierarchicalDataTemplate>

            <HierarchicalDataTemplate x:Key="SolutionTemplate" ItemsSource="{Binding Path=Levels}" ItemTemplate="{StaticResource LevelTemplate}">
                <TextBlock Text="{Binding Path=Name}" />
            </HierarchicalDataTemplate>

        </Grid.Resources>
        <TreeView Name="m_treeview">
            <TreeViewItem Header="{Binding Path=Name}" ItemsSource="{Binding}" ItemTemplate="{StaticResource ResourceKey=SolutionTemplate}">
                <TreeViewItem Header="Levels" ItemsSource="{Binding Path=Levels}" ItemTemplate="{StaticResource ResourceKey=LevelTemplate}" />
                <TreeViewItem Header="Entities"  ItemsSource="{Binding Path=Entities}" ItemTemplate="{StaticResource ResourceKey=EntityTemplate}" />
            </TreeViewItem>
        </TreeView>
    </Grid>

Ca, ca marche presque comme je veux, hormis 2 choses :

  1. J’arrive pas a afficher la recursivité entre GameAsset et GameEntity (oui, ca parait etre une mauvaise idée ce genre de recursivité, mais la n’est pas trop le probleme).
    Vu que pour utiliser une StaticResource, il faut qu’elle soit avant, c’est le serpent qui se mort la queue, et soit je perds l’affichage des Assets, soit je perds l’affichage des Entity.

Pour combler ca, j’ai tenté en mettant un DataType sur le HierarchicalDataTemplate, comme ca :

<Grid Name="m_grid">
        <Grid.Resources>
            <HierarchicalDataTemplate DataType="ds:GameAsset"  x:Key="AssetTemplate">
                <TextBlock Text="{Binding Path=Name}" />
            </HierarchicalDataTemplate>

            <HierarchicalDataTemplate DataType="ds:GameEntity"  x:Key="EntityTemplate" ItemsSource="{Binding Path=Assets}">
                <TextBlock Text="{Binding Path=Name}" />
            </HierarchicalDataTemplate>

            <HierarchicalDataTemplate x:Key="LevelTemplate" ItemsSource="{Binding Path=Entities}">
                <TextBlock Text="{Binding Path=Name}" />
            </HierarchicalDataTemplate>

            <HierarchicalDataTemplate x:Key="SolutionTemplate" ItemsSource="{Binding Path=Levels}" ItemTemplate="{StaticResource LevelTemplate}">
                <TextBlock Text="{Binding Path=Name}" />
            </HierarchicalDataTemplate>

        </Grid.Resources>
        <TreeView Name="m_treeview">
            <TreeViewItem Header="{Binding Path=Name}" ItemsSource="{Binding}" ItemTemplate="{StaticResource SolutionTemplate}">
                <TreeViewItem Header="Levels" ItemsSource="{Binding Path=Levels}" ItemTemplate="{StaticResource LevelTemplate}" />
Celui la :      <TreeViewItem Header="Entities" ItemsSource="{Binding Path=Entities}"/>
            </TreeViewItem>
        </TreeView>
    </Grid>

Ce qui fonctionne pour les Entities qui sont sur les Levels, sur les Asset qui sont sur les Entities,
mais pas sur les Entities qui sont sur mon TreeViewItem « Entities » (celui qui est indiqué dans le code).

Sans compter que ca crash des que je vais mettre sur ce TreeViewItem un truc pour l’aider un peu, genre ca : ItemTemplate="{StaticResource EntityTemplate}".

La question que j’ai donc, c’est comment arriver a afficher cette recursivité entre Asset et Entity. Le plus simplement possible, j’imagine que ca peut etre fait en xaml, mais je me plante ptet completement aussi.

Et le 2) que tout le monde attends :

Comment faire pour se debarrasser des TreeviewItem qui sont set a la main dans le TreeView, et generer 2 items automatiquement, avec 2 bindings differents. (Genre un pour le noeud Levels, un pour le noeud Entities), vu que je vais retomber sur le meme probleme avec GameAsset, qui contient des GameAsset et des GameEntities, ca m’arrangerai de set tout dans le xaml et zou.

Autant ca me derange pas sur le premier niveau d’avoir a les mettre dans la TreeView, autant, si jamais ils pouvaient etre generés direct, je trouverais ca plus propre. Sachant que pour les sous niveaux, je ne pourrais de toute facon pas faire autrement.

En gros, ping girafologue, que je risque de pinger pas mal les prochains jours (j’ai des listview a faire apres :P).

Voila, merci pour ceux qui repondront, si vous voulez des eclaircissements, je suis la. Je suis bien evidemment pret a faire toute les modifs que vous suggerez, sachant que plus on va eviter de modifier les structures de données, et moins je ferais de classe de wrapping, mieux ca sera :slight_smile:

Update : http://complexdatatemplates.codeplex.com/
Ca fait parfaitement son taff, et voila, mais serieux, etre obligé de mettre tout ca en place pour une pauvre treeview ? Je vois pas trop ou je suis gagnant a le faire en WPF plutot qu’en Winforms.