Mettez en surbrillance toute la ligne TreeViewItem dans WPF

Si je définis TreeViewItem Background, il ne met en évidence que l’en-tête. Comment puis-je mettre en évidence toute la ligne?

J’ai trouvé un post presque en train de résoudre un problème

Mais il y a quelques problèmes: 1. Il ne met pas en évidence toute la ligne 2. L’arbre a le style XP sur Vista. Je voudrais que cela ressemble à Vista, mais si l’utilisateur a changé le thème en XP, il devrait être XP. 3. Tant de XAML …

Des idées, que devrais-je chercher?

Nous y voilà, troisième fois un charme. Si vous voulez quelque chose qui ressemble à ceci.

TreeView pleine largeur

Celui-ci prend un peu plus de travail. Je suis sûr qu’il y a plusieurs façons de procéder, mais cette méthode utilise un convertisseur de longueur et une méthode d’extension TreeViewItem pour obtenir la profondeur. Ces deux éléments sont étroitement liés à l’arborescence visuelle de TreeViewItem, donc si vous commencez à manipuler les modèles, vous risquez d’avoir des problèmes. Encore une fois, voici la partie importante, et ci-dessous le code complet.

                   

Extension TreeViewDepth

 public static class TreeViewItemExtensions { public static int GetDepth(this TreeViewItem item) { TreeViewItem parent; while ((parent = GetParent(item)) != null) { return GetDepth(parent) + 1; } return 0; } private static TreeViewItem GetParent(TreeViewItem item) { var parent = VisualTreeHelper.GetParent(item); while (!(parent is TreeViewItem || parent is TreeView)) { parent = VisualTreeHelper.GetParent(parent); } return parent as TreeViewItem; } } 

LeftMarginMultiplierConverter

 public class LeftMarginMultiplierConverter : IValueConverter { public double Length { get; set; } public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var item = value as TreeViewItem; if (item == null) return new Thickness(0); return new Thickness(Length * item.GetDepth(), 0, 0, 0); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new System.NotImplementedException(); } } 

Contrôle

            

Style complet de TreeViewItem

      

TreeViewItem Header ne s’étire pas?

Ce problème se produit car le modèle par défaut de WPF pour TreeViewItem est défini comme une Grid 3 colonnes par 2 lignes. La première ligne est ItemsPresenter à l’en-tête (en fait une Border ) et la deuxième à l’article ItemsPresenter . Les deux lignes sont rendues visibles ou masquées si nécessaire, afin de réaliser l’expansion de l’arbre lorsque vous cliquez sur le petit sortingangle – qui occupe la colonne zéro de la Grid .

Les deux lignes n’ont besoin que d’une colonne supplémentaire. Par exemple, dans la deuxième ligne, nous ne devons rien avoir à col-0, row-1, car cette partie vide doit être en retrait lorsque IsExpanded a la valeur true. Mais le mystère commence lorsque nous notons que le ItemsPresenter , basé dans col-1, row-1, spécifie Grid.ColumnSpan=2 .

Malheureusement, dans la ligne supérieure, la Border Grid.Column=1 l’en-tête est définie sur Grid.Column=1 … mais pas sur ColumnSpan. Puisque le col-2 de la Grid a la Width=* cela signifie que l’en-tête / la bordure ne s’étire pas horizontalement.

En d’autres termes, il semble que la conception de la grid à 3 colonnes ne sert à rien, sauf pour empêcher spécifiquement l’étirement de s’étirer. Autant que je sache, un simple arrangement 2×2 serait plus souple [edit: voir la note de bas de page 2] et prend en charge soit le non-étirement complet, soit l’en-tête «déchiqueté», via les mécanismes d’alignement WPF classiques.

Idéalement, nous changerions la Grid pour ne plus avoir que 2 colonnes au lieu de 3. Comme ce n’est pas si simple, nous ferons en sorte que l’en-tête ItemsPresenter 2 colonnes , comme le ItemsPresenter le ItemsPresenter .

Ok, voici un petit programme de travail complet et autonome (XAML uniquement) qui démontre – et corrige – le problème:

                        

Si vous exécutez ce programme comme indiqué, vous verrez quelque chose comme ceci. Ceci est le comportement corrigé, qui vous permet de reprendre le contrôle complet du comportement d’étirement de l’en-tête TreeViewItem :

entrer la description de l'image ici

Notez la partie BEGIN / END avec les lignes pointillées dans la source XAML. Fondamentalement, je viens de définir Grid.ColumnSpan=2 sur la Border incriminée, afin qu’elle remplisse la largeur de la Grid . Cet élément est émis par le modèle TreeViewItem . Par conséquent, j’ai trouvé qu’un moyen efficace de modifier ses propriétés était d’utiliser un Style ciblage dans le dictionnaire de ressources du Style TreeViewItem . Oui, confus Ce Style est accessible via TreeViewItem.ItemContainerStyle .

Pour voir le comportement cassé (existant), vous pouvez commenter la partie entre les lignes pointillées:

entrer la description de l'image ici

Vous pouvez également définir ces styles dans un dictionnaire de ressources plutôt que d’utiliser la propriété ItemContainerStyle comme je l’ai fait ici. Je l’ai fait de cette façon car il réduit la scope du correctif, de sorte que Border contrôles Border non liés ne soient pas affectés. Si vous avez besoin d’une méthode plus discriminante pour cibler uniquement ce contrôle, vous pouvez tirer parti du fait qu’il possède Name='Bd' .


[edit:] Cette solution n’utilise pas de reflection! Ne soyez pas effrayé par les données démo insignifiantes – cela n’a rien à voir avec ce problème; c’était le moyen le plus simple de récupérer des données hiérarchiques à des fins de démonstration, tout en gardant le programme entier minuscule.


[edit # 2:] Je me suis juste rendu compte que ce que les concepteurs essayaient d’éviter avec l’arrangement de grid 3×2 était l’effet inesthétique suivant (exagéré ici par une capture d’écran zoomée). Donc, si vous adoptez l’une des solutions de cette page, soyez prévenu que vous pourriez ne pas vouloir cela:

entrer la description de l'image ici

Si vous voulez dire quelque chose comme cette capture d’écran

Largeur totale TreeViewItem http://www.bendewey.com/code/treeViewFullWidth2.png

Mise à jour Comme noté cet exemple a la chute d’être en retrait sur les sous-éléments

Largeur totale TreeViewItem http://www.bendewey.com/code/treeViewFullWidth2a.png

Alors cela devrait vous aider. Son également basé sur http://msdn.microsoft.com/en-us/library/ms788727.aspx vous pouvez changer le gabarit de TreeViewItem à un StackPanel et définir le paramètre ItemsPanel Left Margin à 19. Dans l’arbre, vous définissez le HorizontalContentAlignment = “Étendue”. Je joins la ressource entière ci-dessous, mais voici la partie importante.

                 

Contrôle

         

Ressources

      

Si vous voulez dire quelque chose comme cette capture d’écran

LineItem Hightlighting dans un TreeView http://www.bendewey.com/code/treeViewFullWidth.png

Alors cela devrait vous aider. Son basé sur http://msdn.microsoft.com/en-us/library/ms788727.aspx vous pouvez apporter des modifications à la disposition de la grid de TreeViewItem. Fondamentalement, vous supprimez la troisième colonne. Dans le TreeView, vous définissez ensuite HorizontalContentAlignment = “Stretch”. Je joins la ressource entière ci-dessous, mais voici la partie importante.

             

Contrôle

         

Ressources

      

C’est de loin la solution la plus simple. Créez simplement un rectangle, appelez-le Hb, et définissez sa marge à -100px et non visible. Ne le définissez que sur Visible lorsque vous l’avez sélectionné ou sur la souris. C’est un hack, mais vous pouvez utiliser jusqu’à 5 niveaux de TreeViewItems nesteds (100> 19 * 5)

                   

Source du problème lorsque TreeView est utilisé avec ItemsSource, référencé à partir du texte du lien , j’ai modifié du code de la classe TreeViewItemExtensions:

 public static class TreeViewItemExtensions { public static int GetDepth(this TreeViewItem item) { while (GetSelectedTreeViewItemParent(item) != null) { var parent = GetSelectedTreeViewItemParent(item); if (parent != null) return parent.GetDepth() + 1; item = parent; } return 0; } public static TreeViewItem GetSelectedTreeViewItemParent(this TreeViewItem item) { DependencyObject parent = VisualTreeHelper.GetParent(item); while (!(parent is TreeViewItem || parent is TreeView)) { parent = VisualTreeHelper.GetParent(parent); } return parent as TreeViewItem; } } 

Utilisé quelque chose comme theseven7 pour faciliter l’utilisation du code de bendewey avec des TreeViewItems basés sur des modèles …

  public static int GetDepth(this TreeViewItem item) { FrameworkElement elem = item; var parent = VisualTreeHelper.GetParent(item); var count = 0; while (parent != null && !(parent is TreeView)) { var tvi = parent as TreeViewItem; if (parent is TreeViewItem) count++; parent = VisualTreeHelper.GetParent(parent); } return count; } 

J’ai réussi cela en copiant le ItemContainerStyle en utilisant blend, en donnant un nom à la grid dans laquelle l’élément est placé, puis en définissant l’arrière-plan de la grid.

Pour une approche basée uniquement sur XAML, j’ai pris l’une des solutions de Bendewey et je l’ai un peu transformée en une solution plus simple:

Le style ci-dessous doit permettre aux éléments Treeview de couvrir:

  

Pour le faire fonctionner et s’effondrer comme un bon Treeview, les déclencheurs ci-dessous devraient permettre ceci:

                              

Juste imbriquer les déclencheurs dans le modèle de contrôle. Les couleurs / padding / design devront être ajustés pour répondre à vos propres besoins, mais ce qui précède devrait être une idée très simple sur une base XAML uniquement.