Hola a todos
Logical Tree
<RichTextBox>
<FlowDocument>
<Paragraph>
Hola <Rectangle Width='10' Height='10' Fill='Red' />
</Paragraph>
</FlowDocument>
</RichTextBox>
Si miramos el Xaml escrito aquí, veremos que tenemos un control Rectangle dentro de un Paragraph que a su vez se encuentra en un FlowDocument, contenido por un RichTextBox. Así si queremos obtener el Padre lógico del control rectangle este será el control Paragraph pues es quien lo contiene. Esta secuencia es la que nos devolvería el Logical Tree, más adelante veremos este mismo ejemplo con el Visual Tree para observar las diferencias entre ambos.
Este es un ejemplo del resultado de recorrer el árbol lógico del Xaml que tenemos arriba:
Visual Tree
El árbol visual de una ventana WPF contiene información acerca de los controles representados gráficamente en la misma. De esta forma, siguiendo el ejemplo anterior de la Ventana, y como podemos ver en el gráfico anterior, de la Ventana no se desprenderá directamente el contenido de la misma, primero tendremos los controles que componen la plantilla de la ventana y bajo el contentpresenter de la misma encontraremos el resto de controles, junto a su composición interna.
<RichTextBox>
<FlowDocument>
<Paragraph>
Hola <Rectangle Width='10' Height='10' Fill='Red' />
</Paragraph>
</FlowDocument>
</RichTextBox>
En este caso, si queremos obtener el Padre visual de nuestro rectangle usando el árbol visual este nos devolverá como control padre el RichTextBox, en vez del Paragraph, pues los controles Paragraph, FlowDocument, etc… son considerados elementos inline y no controles. Este es un ejemplo del resultado de recorrer el árbol visual del Xaml que tenemos arriba:
Diferencias entre Logical Tree y Visual Tree
Como podéis existen grandes diferencias entre el Árbol Lógico y Visual, y sin duda dependiendo de la situación nos será útil recorrer uno u otro, pero, ¿Cuando usar cada uno? Aquí tenéis las principales características de cada uno:
- Logical Tree:
- Responsable de la herencia de valores de las DependencyProperties
- Resuelve referencias a DynamicResources
- Busqueda de Nombre de elementos para Binding
- Pasar RoutedEvents a ancestros.
- Visual Tree:
- Dibujado de elementos Visuales
- Propagación de opacidad de elementos
- Propagación de LayoutTransform y RenderTransform
- Propagación de la propiedad IsEnabled
- Hit Testing
- RelativeSource (FindAncestor)
Conclusión
Para poder trabajar con estos arboles disponemos de dos clases en WPF: VisualTreeHelper y LogicalTreeHelper que nos ofrecen métodos para movernos en el árbol de cada uno de forma sencilla, Como ejemplo os dejo dos métodos recursivos que recorren el árbol lógico y el visual añadiendo a un treeview todas las ocurrencias a partir de un control dado:
'Obtenemos todos los controles hijos visuales del control base indicado.
Private Sub Recursive_GetVisualChildrens(ByVal BaseControl As DependencyObject,
ByVal ParentNode As TreeViewItem)
If VisualTreeHelper.GetChildrenCount(BaseControl) > 0 Then
For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(BaseControl) - 1
Dim Hijo As New DependencyObject()
Hijo = VisualTreeHelper.GetChild(BaseControl, i)
Dim Nodo As New TreeViewItem
Nodo.Header = Hijo.DependencyObjectType.Name
Recursive_GetVisualChildrens(Hijo, Nodo)
ParentNode.Items.Add(Nodo)
Next
End If
End Sub
'Obtenemos todos los controles hijos lógicos del control base indicado.
Private Sub Recursive_GetLogicalChildrens(ByVal BaseControl As DependencyObject,
ByVal ParentNode As TreeViewItem)
For Each Hijo As Object In LogicalTreeHelper.GetChildren(BaseControl)
Dim Nodo As New TreeViewItem
Nodo.Header = Hijo.GetType().Name
Try
Recursive_GetLogicalChildrens(CType(Hijo, DependencyObject), Nodo)
Catch ex As Exception
End Try
ParentNode.Items.Add(Nodo)
Next
End Sub
Y como ayuda y demostración os dejo una aplicación WPF que hace uso de estos métodos para que juguéis con ella: