Как обновить древовидную структуру при изменении ItemsSource? - PullRequest
3 голосов
/ 11 ноября 2011

Мой TreeView привязан к ObservableCollection и использует HierarchicalDataTemplates.

Я получаю модели из веб-службы.

Только когда пользователи щелкают узел в дереве, вызов веб-службы будет отправляться для получения его дочерних элементов.

Мое приложение имеет TabControl, TreeView находится на одной вкладке, другая вкладка имеет сетку данных, некоторые данные выбираются из дерева.Если щелкнуть правой кнопкой мыши элемент в сетке данных, я хочу найти его в древовидной структуре.Но теперь проблема заключается в том, что, когда я повторяю древовидное представление, скажем, у меня есть элемент с именем

A.A1.A11

, и в моем TreeView есть 3 элемента в первомуровень:

A
B
C

когда я найду A.A1.A11 , я хочу развернуть A,A1 и выделите A11.

когда я итерирую древовидное представление, сначала я нахожу A, оно соответствует первому пути A.A1.A11, поэтому я отправляю запрос веб-службы для получения дочерних элементов A.

Как только я получаю это, DataContext TreeViewItem из A обновляется, но сам TreeViewItem нет.

Поэтому, когда я проверяю A.Items, он пуст, и итерация не может продолжаться.

Как я могу обновить TreeVuew & TreeViewItem при изменении его ItemsSource?

вот xaml для определения дерева

<TreeView x:Name="TreeRoot" 
          ItemsSource="{Binding RootItems}" 
          TreeViewItem.Expanded="TreeViewExpanded"
          TreeView.SelectedItemChanged="TreeRootSelectedItemChanged"
          ContextMenu="{StaticResource DataGridContextMenu}"
          PreviewKeyDown="TreeViewKeyDown"
          PreviewMouseLeftButtonDown="TreeViewPreviewLeftMouseButtonDown"
          PreviewMouseMove="TreeViewPreviewMouseMove" >
    <TreeView.Resources>
        <HierarchicalDataTemplate 
            DataType="{x:Type m:TreeModelBase}" 
            ItemsSource="{Binding Children}">    
            <StackPanel>
                <Image Source="{Binding ImageFilePath}" />
                <TextBlock Text="{Binding Name}" />
                <!-- other items removed for brevity -->
                <StackPanel.Style>
                <Style TargetType="{x:Type StackPanel}">
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding IsSelected}"
                                     Value="True">  
                        <Setter Property="Background" Value="DodgerBlue"/>
                        <Setter Property="TextBlock.Foreground" 
                                Value="White"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding IsSelected}"
                                     Value="False">  
                        <Setter Property="Background" Value="White"/>
                        <Setter Property="TextBlock.Foreground" 
                                Value="Black"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </StackPanel.Style>
            </StackPanel>
        </HierarchicalDataTemplate>
    </TreeView.Resources>
</TreeView>

Ответы [ 4 ]

3 голосов
/ 11 ноября 2011

Реализованы ли в RootItems INotifyProperty, и вы вызываете NotifyPropertyChanged? Коллекции должны быть ObservableCollection (не списком), чтобы пользовательский интерфейс мог знать об обновлениях.

0 голосов
/ 02 февраля 2016

Если вы используете DataContext и правильную технику привязки данных, обновление TreeViewItem может быть достигнуто путем подключения PropertyChanged к каждому элементу и получения TreeViewItem, как указано ниже (сброс DataContext и шаблона элемента дерева). ). В этом примере обновляются только элементы 2-го уровня (второе условие), которые, конечно, могут быть легко расширены.

В моем случае ElementItem является базовым классом для каждого элемента в ObservableList и реализует INotifyProperty.

    ...

    itemInObservableList.PropertyChanged += Ep_PropertyChanged;

    ...

    private void Ep_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
            var twi = this.pageList.ItemContainerGenerator.ContainerFromItem(
                (sender as ElementItem).Parent ) as TreeViewItem;
            if (twi != null)
            {
                var twii = twi.ItemContainerGenerator.ContainerFromItem(sender) as TreeViewItem;
                if (twii != null)
                {
                 //second level items refresh   
                    var dc = twii.DataContext;
                    var tpl = twii.Template;
                    twii.DataContext = null;
                    twii.Template = null;
                    twii.DataContext = sender ;
                    twii.Template = tpl;
                    twii.UpdateLayout();
                }  
            }
    }
0 голосов
/ 14 ноября 2011

Я нашел и сумел заставить его работать. но это действительно не оптимально на всех. Что я сделал, сначала выполните итерацию viewModel, отправьте запрос веб-службы для получения дочерних элементов A, а затем отправьте другой запрос для получения дочерних элементов A1. Это первый проход. Во-вторых, ищите древовидное представление от корня и генерируйте ItemContainers во время итерации. Сначала найдите корень дерева, найдите узел A (treeviewItem), затем примените шаблон, получите контейнер из ItemContainerGenerator (см. Подробнее @ Как обновить представление дерева при изменении ItemsSource? ), затем я могу найти элемент на дерево и расширить свой путь. Кто-нибудь знает лучший способ, дайте мне знать. спасибо

0 голосов
/ 11 ноября 2011

При заполнении потомков TreeViewItem вы не обновляете DataContext, вы обновляете ItemsSource.Поэтому после того, как служба получит дочерние элементы для A, вам нужно назначить результирующий список (или ObservableCollection) для A.ItemsSource.

...