Привязка к данным WPF TreeView со смешанными типами и категоризированными элементами поддеревьевидения

#wpf #xaml #treeview

#wpf #xaml #представление дерева

Вопрос:

Я пытаюсь создать TreeView в WPF, который имеет категории.

В основном структура выглядит следующим образом:

 Root  
 |_
 | Cat A
 |_
 | Cat B
 |_
   Cat C
  

Каждая категория привязана к отдельной наблюдаемой коллекции. Большинство моих категорий очень просты. Элемент TreeViewItem, который является категорией, имеет набор ItemsSource, и в нем нет иерархии. Однако у меня есть категория, которая должна быть представлена в специальной иерархии.

Изображение, которое «Cat C» в приведенном выше дереве затем становится таким:

 Servers
  |_
  | [SERVER A's DISPLAY NAME]
  |  |_
  |  | Namespaces
  |  |  |_
  |  |_   [NAMESPACE alpha's DISPLAY NAME]
  |  | Deployments
  |  |  |_
  |  |_   [DEPLOYMENT 1's DISPLAY NAME]
  |_   Configuration File
    [SERVER B's DISPLAY NAME]
  

По сути, я хочу, чтобы жестко закодированный родительский элемент TreeViewItem имел статический заголовок. Затем у этого элемента должна быть коллекция элементов с отображаемыми их именами. Для каждого дочернего элемента исходного родительского элемента должно быть три статических элемента, которые имеют динамический список дочерних элементов.

Написание этого заставляет меня думать, что это должно быть очень упрощенной проблемой для решения. Однако, поиграв с XAML пару дней, я не могу заставить иерархию работать. Ниже приведен самый дальний, который я смог получить. Я использовал составную коллекцию, называемую дочерними элементами, чтобы объединить пространства имен, развертывания и файл конфигурации в одну коллекцию. Однако я не могу их разделить.

 <TreeViewItem ItemsSource="{Binding Path=Configuration.Servers}" 
                      IsExpanded="True" >
            <TreeViewItem.ItemContainerStyle>
                <Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}">
                    <Setter Property="IsExpanded" Value="True"/>
                </Style>
            </TreeViewItem.ItemContainerStyle>

            <TreeViewItem.HeaderTemplate>
                <DataTemplate>
                    <Border Margin="0,2,2,0">
                        <StackPanel Orientation="Horizontal">
                            <Image Source="/WPF;component/Images/server_chart.png"
                                   Margin="0,0,5,0"/>
                            <TextBlock Text="Cognos Servers" />
                        </StackPanel>
                    </Border>
                </DataTemplate>
            </TreeViewItem.HeaderTemplate>

            <TreeViewItem.Resources>
                <HierarchicalDataTemplate ItemSource="{Binding Path=Children}" DataType="{x:Type local:Server}">
                    <HierarchicalDataTemplate.ItemContainerStyle>
                        <Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}" >
                            <Setter Property="IsExpanded" Value="True"/>
                        </Style>
                    </HierarchicalDataTemplate.ItemContainerStyle>
                    <TextBlock Text="{Binding DisplayName}" PreviewMouseRightButtonDown="OnPreviewMouseRightButtonDown">
                        <TextBlock.ContextMenu>
                            <ContextMenu>
                                <MenuItem Header="Refresh" Click="TreeItemMenu_AddNewClient">
                                    <MenuItem.Icon>
                                        <Image Source="/WPF;component/Images/arrow_refresh.png" />
                                    </MenuItem.Icon>
                                </MenuItem>
                                <MenuItem Header="Add Client..." Click="TreeItemMenu_AddNewClient" />
                                <Separator />
                                <MenuItem Header="Remove" Click="TreeItemMenu_RemoveClick">
                                    <MenuItem.Icon>
                                        <Image Source="/WPF;component/Images/server_delete.png" />
                                    </MenuItem.Icon>
                                </MenuItem>
                            </ContextMenu>
                        </TextBlock.ContextMenu>
                    </TextBlock>
                </HierarchicalDataTemplate>

                <HierarchicalDataTemplate ItemsSource="{Binding Clients}" DataType="{x:Type local:Namespace}">
                    <HierarchicalDataTemplate.ItemContainerStyle>
                        <Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}" >
                            <Setter Property="IsExpanded" Value="True"/>
                        </Style>
                    </HierarchicalDataTemplate.ItemContainerStyle>
                    <TextBlock Text="{Binding DisplayName}" PreviewMouseRightButtonDown="OnPreviewMouseRightButtonDown" />
                </HierarchicalDataTemplate>

                <DataTemplate DataType="{x:Type local:Client}">
                    <TextBlock Text="{Binding DisplayName}"
                               ContextMenu="{StaticResource ResourceKey=ContextMenuTreeItem}" 
                               PreviewMouseRightButtonDown="OnPreviewMouseRightButtonDown" />
                </DataTemplate>
            </TreeViewItem.Resources>
  

Ответ №1:

Майк,

Смешивание статических данных и данных модели, вероятно, не приведет вас туда, куда вы хотите. Вам нужно будет создать фактическую ViewModel, содержащую статические узлы и т.д. Я настоятельно рекомендую учебные пособия Джоша Смита по TreeView ViewModel. Это первый, но посмотрите вокруг для получения дополнительной информации. Он один из самых осведомленных разработчиков в этой области. Мы добились большого успеха, следуя его рекомендациям.

Комментарии:

1. Ваш ответ правильный. Думаю, я мог бы сказать, что прошел половину пути. Я сопротивлялся созданию ViewModel для категоризированных заголовков. После того, как я создал общую модель для представления категоризированного заголовка, это сработало лучше. Все еще не так чисто, как мне хотелось бы, но теперь это работает.