Jak uzyskać TreeViewItem z pozycji hierarchicznej?

Mam TreeView, który używa HierarchicalDataTemplate do wiązania swoich danych.

Wygląda to tak:

<TreeView x:Name="mainTreeList" ItemsSource="{Binding MyCollection}>
  <TreeView.Resources>
    <HierarchicalDataTemplate 
     DataType="{x:Type local:MyTreeViewItemViewModel}" 
     ItemsSource="{Binding Children}">
      <!-- code code code -->
    </HierarchicalDataTemplate>
  </TreeView.Resources>
</TreeView>

Teraz z kodu-za głównym oknem Chcę pobrać bieżący wybrany TreeViewItem. Jeśli jednak użyję:

this.mainTreeList.SelectedItem;

SelectedItem jest typu MyTreeViewItemViewModel. Ale chcę dostać "rodzica" lub "związany" TreeViewItem. Nie przekazuję tego do mojego TreeViewItemModel obiektu(nawet nie wiem jak).

Jak mogę to zrobić?

Author: GEOCHET, 2009-03-06

10 answers

Z wpisu Bea Stollnitz na blogu o tym, spróbuj

TreeViewItem item = (TreeViewItem)(mainTreeList
    .ItemContainerGenerator
    .ContainerFromIndex(mainTreeList.Items.CurrentPosition));
 20
Author: Cameron MacFarland,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-03-06 08:47:14
TreeViewItem item = (TreeViewItem)(mainTreeList
    .ItemContainerGenerator
    .ContainerFromIndex(mainTreeList.Items.CurrentPosition));

Nie działa (dla mnie) jako mainTreeList.Pozycji.CurrentPosition w widoku drzewa za pomocą hierarchicznej tablicy zawsze będzie wynosić -1.

Podobnie jak poniżej jako mainTreeList.Pozycji.CurrentItem w widoku drzewa za pomocą hierarchicznej tabeli zawsze będzie null.

TreeViewItem item = (TreeViewItem)mainTreeList
    .ItemContainerGenerator
    .ContainerFromItem(mainTreeList.Items.CurrentItem);

Zamiast tego musiałem ustawić ostatni wybrany TreeViewItem w kierowanym TreeViewItem.Wybrane zdarzenie, które pojawia się w widoku drzewa (same TreeViewItem nie istnieją w czasie projektowania, ponieważ używamy hierarchicznej tabeli).

Zdarzenie może być uchwycone w XAML Tak:

<TreeView TreeViewItem.Selected="TreeViewItemSelected" .../> 

Wtedy ostatni wybrany TreeViewItem może być ustawiony w zdarzeniu w następujący sposób:

    private void TreeViewItemSelected(object sender, RoutedEventArgs e)
    {
        TreeViewItem tvi = e.OriginalSource as TreeViewItem;

        // set the last tree view item selected variable which may be used elsewhere as there is no other way I have found to obtain the TreeViewItem container (may be null)
        this.lastSelectedTreeViewItem = tvi;

        ...
     }
 31
Author: markmnl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-24 08:27:16

Natknąłem się na ten sam problem. Musiałem dostać się do TreeViewItem, aby móc go wybrać. Potem zdałem sobie sprawę, że mogę po prostu dodać właściwość IsSelected do mojego ViewModel, który następnie związany z TreeViewItems IsSelectedProperty. Można to osiągnąć za pomocą ItemContainerStyle:

<TreeView>
            <TreeView.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}">
                    <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/>
                    <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
                </Style>
            </TreeView.ItemContainerStyle>
</TreeView>

Teraz, jeśli chcę mieć element w widoku drzewa wybrany, po prostu wywołuję IsSelected na mojej klasie ViewModel bezpośrednio.

Mam nadzieję, że to komuś pomoże.
 7
Author: santiagoIT,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-09-21 17:20:45
TreeViewItem item = (TreeViewItem)(mainTreeList
    .ItemContainerGenerator
    .ContainerFromIndex(mainTreeList.Items.CurrentPosition)); gives first item in the TreeView because CurrentPosition is always 0.

A może

TreeViewItem item = (TreeViewItem)(mainTreeList
    .ItemContainerGenerator
    .ContainerFromItem(mainTreeList.SelectedItem)));
To działa lepiej dla mnie.
 5
Author: kitndirangu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-05-24 08:32:26

Zainspirowany odpowiedzią Fëanora, starałem się uczynić TreeViewItem łatwo dostępnym dla każdego elementu danych, dla którego został utworzony TreeViewItem.

Chodzi o to, aby dodać do modelu widoku pole typu TreeViewItem, również wyeksponowane poprzez interfejs, i aby TreeView automatycznie wypełniało je po utworzeniu kontenera TreeViewItem.

Odbywa się to poprzez podklasowanie TreeView i dołączenie zdarzenia do ItemContainerGenerator, które rejestruje TreeViewItem Po utworzeniu. Gotchas to fakt, że TreeViewItemS są tworzone leniwie, więc w pewnych momentach może ich nie być.

Od czasu opublikowania tej odpowiedzi, rozwinąłem ją dalej i używałem jej przez długi czas w jednym projekcie. Do tej pory nie ma żadnych problemów, poza faktem, że narusza to MVVM (ale także oszczędza mnóstwo kotła dla prostych przypadków). Źródło tutaj .

Użycie

Wybierz rodzica zaznaczonego elementu i zwiń go, upewniając się, że znajduje się w widok:

...
var selected = myTreeView.SelectedItem as MyItem;
selected.Parent.TreeViewItem.IsSelected = true;
selected.Parent.TreeViewItem.IsExpanded = false;
selected.Parent.TreeViewItem.BringIntoView();
...

<Window ...
        xmlns:tvi="clr-namespace:TreeViewItems"
        ...>
    ...
    <tvi:TreeViewWithItem x:Name="myTreeView">
        <HierarchicalDataTemplate DataType = "{x:Type src:MyItem}"
                                  ItemsSource = "{Binding Children}">
            <TextBlock Text="{Binding Path=Name}"/>
        </HierarchicalDataTemplate>
    </tvi:TreeViewWithItem>
    ...
</Window>
class MyItem : IHasTreeViewItem
{
    public string Name { get; set; }
    public ObservableCollection<MyItem> Children { get; set; }
    public MyItem Parent;
    public TreeViewItem TreeViewItem { get; set; }
    ...
}

Kod

public class TreeViewWithItem : TreeView
{
    public TreeViewWithItem()
    {
        ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;
    }

    private void ItemContainerGenerator_StatusChanged(object sender, EventArgs e)
    {
        var generator = sender as ItemContainerGenerator;
        if (generator.Status == GeneratorStatus.ContainersGenerated)
        {
            int i = 0;
            while (true)
            {
                var container = generator.ContainerFromIndex(i);
                if (container == null)
                    break;

                var tvi = container as TreeViewItem;
                if (tvi != null)
                    tvi.ItemContainerGenerator.StatusChanged += ItemContainerGenerator_StatusChanged;

                var item = generator.ItemFromContainer(container) as IHasTreeViewItem;
                if (item != null)
                    item.TreeViewItem = tvi;

                i++;
            }
        }
    }
}

interface IHasTreeViewItem
{
    TreeViewItem TreeViewItem { get; set; }
}
 4
Author: Roman Starkov,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-31 20:08:57

Spróbuj czegoś takiego:

    public bool UpdateSelectedTreeViewItem(PropertyNode dateItem, ItemsControl itemsControl)
    {
        if (itemsControl == null || itemsControl.Items == null || itemsControl.Items.Count == 0)
        {
            return false;
        }
        foreach (var item in itemsControl.Items.Cast<PropertyNode>())
        {
            var treeViewItem = itemsControl.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
            if (treeViewItem == null)
            {
                continue;
            }
            if (item == dateItem)
            {
                treeViewItem.IsSelected = true;
                return true;
            }
            if (treeViewItem.Items.Count > 0 && UpdateSelectedTreeViewItem(dateItem, treeViewItem))
            {
                return true;
            }
        }
        return false;
    }
 2
Author: Kevin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-07 05:04:01

Pojedynczy ' ItemContainerGenerator.ContainerFromItem " lub " ItemContainerGenerator.Wywołanie ItemContainerGenerator nie może znaleźć TreeViewItem skojarzonego z obiektem tree view, ponieważ jest oddzielone kontrolerem elementu tree view i danymi elementu tree view. Aby użyć 'ItemContainerGenerator, konieczne jest utworzenie funkcji rekurencyjnej.ContainerFromItem " i " ItemContainerGenerator.ItemContainerGenerator', aby zlokalizować TreeViewItem w widoku drzewa. Przykładowa funkcja rekurencyjna może wyglądać like:

private TreeViewItem GetTreeViewItemFromObject(ItemContainerGenerator container, object tvio)
{
    var item = container.ContainerFromItem(tvio) as TreeViewItem;
    if (item != null)
    {
        return item;
    }

    for (int i = 0; i < container.Items.Count; i++)
    {
        var subContainer = (TreeViewItem)container.ContainerFromIndex(i);
        if (subContainer != null)
        {
            item = GetTreeViewItemFromObject(subContainer.ItemContainerGenerator, tvio);
            if (item != null)
            {
                return item;
            }
        }
    }

    return null;
}

Wywołane przez var target = GetTreeViewItemFromObject (treeView.ItemContainerGenerator, item);

Funkcja rekurencyjna działa tylko po 'ItemContainerGenerator w widoku drzewa.Status " to "ContainersGenerated". Tak więc podczas okresu wyświetlania inicjalizacji 'GetTreeViewItemFromObject' nie działa.

 1
Author: William,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-06-08 19:44:58

Czy potrzebujesz TreeViewItem, ponieważ zamierzasz zmodyfikować to, co jest wyświetlane? Jeśli tak jest, polecam użycie stylu do zmiany sposobu wyświetlania elementu zamiast używania code-behind zamiast bezpośredniej modyfikacji TreeViewItem. Powinno być czystsze.

 0
Author: viggity,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-09-22 02:47:08

Jeśli musisz znaleźć element w dzieciach dzieci, możesz użyć rekurencji w następujący sposób

public bool Select(TreeViewItem item, object select) // recursive function to set item selection in treeview
{
    if (item == null)
        return false;
    TreeViewItem child = item.ItemContainerGenerator.ContainerFromItem(select) as TreeViewItem;
    if (child != null)
    {
        child.IsSelected = true;
        return true;
    }
    foreach (object c in item.Items)
    {
        bool result = Select(item.ItemContainerGenerator.ContainerFromItem(c) as TreeViewItem, select);
        if (result == true)
            return true;
    }
    return false;
}
 0
Author: purvin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-09-06 13:27:59

Oto rozwiązanie. rtvEsa to treeview. Hierarchiczny jest szablonem treeview Znacznik sprawia, że rzeczywiste zużycie bieżącego przedmiotu. To nie jest zaznaczona pozycja, to jest aktualna pozycja w sterowaniu drzewa, która używa Hierarchicznegoaldatatemplate.

Pozycji.Obecnie jest częścią wewnętrznego zbioru drzew. Nie można uzyskać wielu różnych danych. Na przykład przedmioty.ParenItem też.

  <HierarchicalDataTemplate ItemsSource="{Binding ChildItems}">

  <TextBox Tag="{Binding ElementName=rtvEsa, Path=Items.CurrentItem }" />

 0
Author: Petar,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-09 07:28:38