Resalte toda la línea TreeViewItem en WPF

Si configuro Background de TreeViewItem, solo resalta el encabezado. ¿Cómo puedo resaltar toda la línea?

He encontrado una publicación que casi resuelve un problema http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/b04f73e2-0b10-4d97-a6da-64df2e30c21d/

Pero hay algunos problemas: 1. No resalta toda la línea 2. El árbol tiene estilo XP en Vista. Me gustaría que se viera de la misma manera en Vista que en el pasado, pero si el usuario cambia el tema a XP, debería ser XP. 3. Tantos XAML …

Alguna idea, ¿qué debería buscar?

Aquí vamos, en tercer lugar un encanto. Si quieres algo que se vea así.

Ancho completo TreeView

Esto lleva un poco más de trabajo. Estoy seguro de que hay muchas maneras de hacerlo, pero este método usa un convertidor de longitud y un método de extensión TreeViewItem para obtener la profundidad. Ambos están estrechamente relacionados con el árbol visual TreeViewItem, por lo que si comienzas a jugar con las plantillas, entonces puedes tener problemas. Nuevamente, aquí está la parte importante, y abajo está el código completo.

                   

Extensión 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(); } } 

Controlar

            

Estilo completo de TreeViewItem

      

El encabezado TreeViewItem no se ampliará?

Este problema se produce porque la plantilla predeterminada de WPF para TreeViewItem está configurada como una Grid 3 columnas por 2 filas. La primera fila es para el “encabezado” (en realidad, un Border ), y la segunda fila es para ItemsPresenter . Las dos filas se hacen visibles u ocultas según sea necesario para lograr la expansión del árbol al hacer clic en el pequeño triángulo, que ocupa la columna cero de la Grid .

Ambas filas realmente solo necesitan una columna adicional. Por ejemplo, en la segunda fila, no debemos tener nada en col-0, fila-1, porque esa parte en blanco debe IsExpanded cuando IsExpanded es verdadero. Pero el misterio comienza cuando notamos que ItemsPresenter , basado en col-1, row-1, especifica Grid.ColumnSpan=2 .

Desafortunadamente en la fila superior, el Border que contiene el encabezado se establece en Grid.Column=1 … pero no en ColumnSpan. Como el col-2 de la Grid tiene Width=* esto significa que el encabezado / borde no se extenderá horizontalmente.

En otras palabras, parece que el diseño de cuadrícula de 3 columnas no tiene otro propósito que el de evitar específicamente que el encabezado se expanda. Por lo que puedo decir, una disposición simple de 2×2 sería más flexible [edite: vea la nota de pie de página n. ° 2], y apoye el estiramiento completo o el encabezado ‘irregular’ sin estirar, a través de los mecanismos de alineación de WPF normales.

Idealmente, cambiaríamos la Grid para que tenga solo 2 columnas en lugar de 3. Como no es tan fácil, en su lugar haremos que el encabezado abarque 2 columnas , al igual que lo hace el ItemsPresenter .

Bien, aquí hay un progtwig de trabajo pequeño, completo e independiente (solo XAML) que demuestra (y soluciona) el problema:

                        

Si ejecuta este progtwig como se muestra, verá algo como esto. Este es el comportamiento fijo, que le permite recuperar el control total sobre el comportamiento de estiramiento del encabezado TreeViewItem :

enter image description here

Observe la parte BEGIN / END con las líneas punteadas en la fuente XAML. Básicamente, acabo de establecer Grid.ColumnSpan=2 en el Grid.ColumnSpan=2 ofensivo, de modo que llene el ancho estirado de la Grid . Ese elemento es emitido por la plantilla TreeViewItem , así que descubrí que una forma efectiva de alterar sus propiedades es a través de un Style orientación en el diccionario de recursos del Style TreeViewItem . Sí, confuso. Ese Style se accede a través de TreeViewItem.ItemContainerStyle .

Para ver el comportamiento roto (existente), puede comentar la parte entre las líneas punteadas:

enter image description here

También puede establecer estos estilos en algún diccionario de recursos, en lugar de usar la propiedad ItemContainerStyle como lo hice aquí. Lo hice de esta manera porque minimiza el scope de la corrección, por lo que Border controles de Border no relacionados no se verán afectados. Si necesita una forma más discriminatoria de orientar solo este control, puede aprovechar el hecho de que tiene Name='Bd' .


[edit:] ¡ Esta solución no usa reflexión! No te asustes con los datos de demostración sin sentido: no tiene nada que ver con este problema; era simplemente la forma más fácil de obtener algunos datos jerárquicos con fines de demostración, mientras se mantenía minúsculo todo el progtwig.


[edit # 2:] Me acabo de dar cuenta de que lo que los diseñadores estaban tratando de evitar con la disposición de la cuadrícula 3×2 fue el siguiente efecto antiestético (exagerado aquí por una captura de pantalla alejada). Por lo tanto, si adopta una de las soluciones de esta página, tenga en cuenta que es posible que no desee esto:

enter image description here

Si te refieres a algo como esta captura de pantalla

Ancho completo TreeViewItem http://www.bendewey.com/code/treeViewFullWidth2.png

Actualización Como se señaló, este ejemplo tiene la desventaja de tener sangría en los subelementos

Ancho completo TreeViewItem http://www.bendewey.com/code/treeViewFullWidth2a.png

Entonces esto debería ayudarte. También se basa en http://msdn.microsoft.com/en-us/library/ms788727.aspx . Puedes cambiar la plantilla de TreeViewItem a StackPanel y establecer el Margen izquierdo de ItemsPanel en 19. Luego, en TreeView, configuras HorizontalContentAlignment = “Tramo”. Adjunto el recurso completo a continuación, pero aquí está la parte importante.

                 

Controlar

         

Recursos

      

Si te refieres a algo como esta captura de pantalla

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

Entonces esto debería ayudarte. Se basa en http://msdn.microsoft.com/en-us/library/ms788727.aspx y puede realizar algunos cambios en el diseño de cuadrícula de TreeViewItem. Básicamente, eliminas la tercera columna. Luego, en TreeView configuras HorizontalContentAlignment = “Stretch”. Adjunto el recurso completo a continuación, pero aquí está la parte importante.

             

Controlar

         

Recursos

      

Esta es, de lejos, la solución más fácil. Simplemente crea un rectángulo, llámalo Hb y configura su valor de minería a -100px y no visible. Solo configúrelo en Visible cuando lo haya seleccionado o pasado el mouse. Es un truco, pero eres bueno para hasta 5 niveles de TreeViewItems nesteds (100> 19 * 5)

                   

Fuente del problema cuando uso TreeView con ItemsSource es, referido desde el texto del enlace , he cambiado algún código de la clase 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; } } 

Usé algo como theseven7 para facilitar el uso del código de Bendewey con TreeViewItems con plantilla …

  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; } 

Logré esto copiando ItemContainerStyle utilizando blend, dando un nombre a la grilla en la que se coloca el elemento y luego estableciendo el fondo de la grilla.

Para un enfoque solo de XAML, tomé una de las soluciones de Bendewey y la dividí un poco en una solución más básica:

El estilo a continuación debería permitir que los artículos Treeview abarquen:

  

Para que funcione y se colapse como una vista en árbol adecuada, los disparadores a continuación deberían permitir esto:

                              

Simplemente anide los desencadenantes dentro de la plantilla de control. Los colores / relleno / diseño deberán ajustarse para satisfacer sus propias necesidades, pero lo anterior debe ser una idea muy básica en una base exclusiva de XAML.