Jak znaleźć TreeViewItem w TreeView
Kontrolka TreeView zapewnia wygodny sposób wyświetlania danych hierarchicznych. TreeView Jeśli element jest powiązany ze źródłem danych, SelectedItem właściwość zapewnia wygodny sposób szybkiego pobierania wybranego obiektu danych. Zazwyczaj najlepiej jest pracować z obiektem danych bazowych, ale czasami może być konieczne programowe manipulowanie danymi zawierającymi TreeViewItemelement . Na przykład może być konieczne programowe rozwinięcie elementu TreeViewItemlub wybranie innego elementu w elemencie TreeView.
Aby znaleźć obiekt TreeViewItem zawierający określony obiekt danych, należy przejść przez każdy poziom obiektu TreeView. Elementy w obiekcie TreeView można również zwirtualizować w celu zwiększenia wydajności. W przypadku, gdy elementy mogą być zwirtualizowane, należy również zrealizować element , TreeViewItem aby sprawdzić, czy zawiera obiekt danych.
Przykład
opis
Poniższy przykład wyszukuje TreeView określony obiekt i zwraca obiekt zawierający TreeViewItemelement . W tym przykładzie zapewnia się utworzenie wystąpienia poszczególnych TreeViewItem elementów podrzędnych, dzięki czemu można wyszukiwać elementy podrzędne. Ten przykład działa również, jeśli element nie używa elementów zwirtualizowanych TreeView .
Uwaga
Poniższy przykład działa dla dowolnego TreeViewmodelu danych, niezależnie od bazowego modelu danych i wyszukuje każdy TreeViewItem do momentu znalezienia obiektu. Inną techniką, która ma lepszą wydajność, jest wyszukiwanie modelu danych dla określonego obiektu, śledzenie jego lokalizacji w hierarchii danych, a następnie znalezienie odpowiedniego TreeViewItemTreeViewelementu w obiekcie . Jednak technika, która ma lepszą wydajność, wymaga znajomości modelu danych i nie może być uogólniona dla danego elementu TreeView.
Kod
/// <summary>
/// Recursively search for an item in this subtree.
/// </summary>
/// <param name="container">
/// The parent ItemsControl. This can be a TreeView or a TreeViewItem.
/// </param>
/// <param name="item">
/// The item to search for.
/// </param>
/// <returns>
/// The TreeViewItem that contains the specified item.
/// </returns>
private TreeViewItem GetTreeViewItem(ItemsControl container, object item)
{
if (container != null)
{
if (container.DataContext == item)
{
return container as TreeViewItem;
}
// Expand the current container
if (container is TreeViewItem && !((TreeViewItem)container).IsExpanded)
{
container.SetValue(TreeViewItem.IsExpandedProperty, true);
}
// Try to generate the ItemsPresenter and the ItemsPanel.
// by calling ApplyTemplate. Note that in the
// virtualizing case even if the item is marked
// expanded we still need to do this step in order to
// regenerate the visuals because they may have been virtualized away.
container.ApplyTemplate();
ItemsPresenter itemsPresenter =
(ItemsPresenter)container.Template.FindName("ItemsHost", container);
if (itemsPresenter != null)
{
itemsPresenter.ApplyTemplate();
}
else
{
// The Tree template has not named the ItemsPresenter,
// so walk the descendents and find the child.
itemsPresenter = FindVisualChild<ItemsPresenter>(container);
if (itemsPresenter == null)
{
container.UpdateLayout();
itemsPresenter = FindVisualChild<ItemsPresenter>(container);
}
}
Panel itemsHostPanel = (Panel)VisualTreeHelper.GetChild(itemsPresenter, 0);
// Ensure that the generator for this panel has been created.
UIElementCollection children = itemsHostPanel.Children;
MyVirtualizingStackPanel virtualizingPanel =
itemsHostPanel as MyVirtualizingStackPanel;
for (int i = 0, count = container.Items.Count; i < count; i++)
{
TreeViewItem subContainer;
if (virtualizingPanel != null)
{
// Bring the item into view so
// that the container will be generated.
virtualizingPanel.BringIntoView(i);
subContainer =
(TreeViewItem)container.ItemContainerGenerator.
ContainerFromIndex(i);
}
else
{
subContainer =
(TreeViewItem)container.ItemContainerGenerator.
ContainerFromIndex(i);
// Bring the item into view to maintain the
// same behavior as with a virtualizing panel.
subContainer.BringIntoView();
}
if (subContainer != null)
{
// Search the next level for the object.
TreeViewItem resultContainer = GetTreeViewItem(subContainer, item);
if (resultContainer != null)
{
return resultContainer;
}
else
{
// The object is not under this TreeViewItem
// so collapse it.
subContainer.IsExpanded = false;
}
}
}
}
return null;
}
/// <summary>
/// Search for an element of a certain type in the visual tree.
/// </summary>
/// <typeparam name="T">The type of element to find.</typeparam>
/// <param name="visual">The parent element.</param>
/// <returns></returns>
private T FindVisualChild<T>(Visual visual) where T : Visual
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(visual); i++)
{
Visual child = (Visual)VisualTreeHelper.GetChild(visual, i);
if (child != null)
{
T correctlyTyped = child as T;
if (correctlyTyped != null)
{
return correctlyTyped;
}
T descendent = FindVisualChild<T>(child);
if (descendent != null)
{
return descendent;
}
}
}
return null;
}
''' <summary>
''' Recursively search for an item in this subtree.
''' </summary>
''' <param name="container">
''' The parent ItemsControl. This can be a TreeView or a TreeViewItem.
''' </param>
''' <param name="item">
''' The item to search for.
''' </param>
''' <returns>
''' The TreeViewItem that contains the specified item.
''' </returns>
Private Function GetTreeViewItem(ByVal container As ItemsControl,
ByVal item As Object) As TreeViewItem
If container IsNot Nothing Then
If container.DataContext Is item Then
Return TryCast(container, TreeViewItem)
End If
' Expand the current container
If TypeOf container Is TreeViewItem AndAlso
Not DirectCast(container, TreeViewItem).IsExpanded Then
container.SetValue(TreeViewItem.IsExpandedProperty, True)
End If
' Try to generate the ItemsPresenter and the ItemsPanel.
' by calling ApplyTemplate. Note that in the
' virtualizing case, even if IsExpanded = true,
' we still need to do this step in order to
' regenerate the visuals because they may have been virtualized away.
container.ApplyTemplate()
Dim itemsPresenter As ItemsPresenter =
DirectCast(container.Template.FindName("ItemsHost", container), ItemsPresenter)
If itemsPresenter IsNot Nothing Then
itemsPresenter.ApplyTemplate()
Else
' The Tree template has not named the ItemsPresenter,
' so walk the descendents and find the child.
itemsPresenter = FindVisualChild(Of ItemsPresenter)(container)
If itemsPresenter Is Nothing Then
container.UpdateLayout()
itemsPresenter = FindVisualChild(Of ItemsPresenter)(container)
End If
End If
Dim itemsHostPanel As Panel =
DirectCast(VisualTreeHelper.GetChild(itemsPresenter, 0), Panel)
' Do this to ensure that the generator for this panel has been created.
Dim children As UIElementCollection = itemsHostPanel.Children
Dim virtualizingPanel As MyVirtualizingStackPanel =
TryCast(itemsHostPanel, MyVirtualizingStackPanel)
For index As Integer = 0 To container.Items.Count - 1
Dim subContainer As TreeViewItem
If virtualizingPanel IsNot Nothing Then
' Bring the item into view so
' that the container will be generated.
virtualizingPanel.BringIntoView(index)
subContainer =
DirectCast(container.ItemContainerGenerator.ContainerFromIndex(index),
TreeViewItem)
Else
subContainer =
DirectCast(container.ItemContainerGenerator.ContainerFromIndex(index),
TreeViewItem)
' Bring the item into view to maintain the
' same behavior as with a virtualizing panel.
subContainer.BringIntoView()
End If
If subContainer IsNot Nothing Then
' Search the next level for the object.
Dim resultContainer As TreeViewItem =
GetTreeViewItem(subContainer, item)
If resultContainer IsNot Nothing Then
Return resultContainer
Else
' The object is not under this TreeViewItem
' so collapse it.
subContainer.IsExpanded = False
End If
End If
Next
End If
Return Nothing
End Function
''' <summary>
''' Search for an element of a certain type in the visual tree.
''' </summary>
''' <typeparam name="T">The type of element to find.</typeparam>
''' <param name="visual">The parent element.</param>
''' <returns></returns>
Private Function FindVisualChild(Of T As Visual)(ByVal visual As Visual) As T
For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(visual) - 1
Dim child As Visual = DirectCast(VisualTreeHelper.GetChild(visual, i), Visual)
If child IsNot Nothing Then
Dim correctlyTyped As T = TryCast(child, T)
If correctlyTyped IsNot Nothing Then
Return correctlyTyped
End If
Dim descendent As T = FindVisualChild(Of T)(child)
If descendent IsNot Nothing Then
Return descendent
End If
End If
Next
Return Nothing
End Function
Poprzedni kod opiera się na niestandardowym VirtualizingStackPanel , który uwidacznia metodę o nazwie BringIntoView
. Poniższy kod definiuje niestandardowy VirtualizingStackPanelelement .
public class MyVirtualizingStackPanel : VirtualizingStackPanel
{
/// <summary>
/// Publically expose BringIndexIntoView.
/// </summary>
public void BringIntoView(int index)
{
this.BringIndexIntoView(index);
}
}
Public Class MyVirtualizingStackPanel
Inherits VirtualizingStackPanel
''' <summary>
''' Publically expose BringIndexIntoView.
''' </summary>
Public Overloads Sub BringIntoView(ByVal index As Integer)
Me.BringIndexIntoView(index)
End Sub
End Class
Poniższy kod XAML pokazuje, jak utworzyć obiekt TreeView , który używa niestandardowego VirtualizingStackPanelelementu .
<TreeView VirtualizingStackPanel.IsVirtualizing="True">
<!--Use the custom class MyVirtualizingStackPanel
as the ItemsPanel for the TreeView and
TreeViewItem object.-->
<TreeView.ItemsPanel>
<ItemsPanelTemplate>
<src:MyVirtualizingStackPanel/>
</ItemsPanelTemplate>
</TreeView.ItemsPanel>
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<src:MyVirtualizingStackPanel/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
Zobacz też
.NET Desktop feedback