Bagikan melalui


Cara: Menemukan TreeViewItem di TreeView

Kontrol TreeView ini menyediakan cara mudah untuk menampilkan data hierarkis. Jika Anda TreeView terikat ke sumber data, SelectedItem properti menyediakan cara mudah bagi Anda untuk mengambil objek data yang dipilih dengan cepat. Biasanya yang terbaik adalah bekerja dengan objek data yang mendasar, tetapi kadang-kadang Anda mungkin perlu memanipulasi data yang berisi TreeViewItemsecara terprogram . Misalnya, Anda mungkin perlu memperluas TreeViewItem, atau memilih item yang berbeda secara terprogram di TreeView.

Untuk menemukan TreeViewItem yang berisi objek data tertentu, Anda harus melintasi setiap tingkat .TreeView Item dalam TreeView juga dapat divirtualisasi untuk meningkatkan performa. Dalam kasus di mana item mungkin divirtualisasi, Anda juga harus menyadari TreeViewItem untuk memeriksa apakah item tersebut berisi objek data.

Contoh

Deskripsi

Contoh berikut mencari TreeView objek tertentu dan mengembalikan objek yang berisi TreeViewItem. Contoh memastikan bahwa masing-masing TreeViewItem dibuat sehingga item turunannya dapat dicari. Contoh ini juga berfungsi jika TreeView tidak menggunakan item virtual.

Catatan

Contoh berikut berfungsi untuk setiap TreeView, terlepas dari model data yang mendasar, dan mencari setiap TreeViewItem hingga objek ditemukan. Teknik lain yang memiliki performa lebih baik adalah mencari model data untuk objek yang ditentukan, melacak lokasinya dalam hierarki data, dan kemudian menemukan yang sesuai TreeViewItem di TreeView. Namun, teknik yang memiliki performa lebih baik membutuhkan pengetahuan tentang model data dan tidak dapat digeneralisasi untuk setiap yang diberikan TreeView.

Kode

/// <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

Kode sebelumnya bergantung pada kustom VirtualizingStackPanel yang mengekspos metode bernama BringIntoView. Kode berikut mendefinisikan kustom VirtualizingStackPanel.

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

XAML berikut menunjukkan cara membuat TreeView yang menggunakan kustom VirtualizingStackPanel.

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

Baca juga