Проблемы с привязкой таблички данных в стиле WPF TreeView

#wpf #xaml #treeview #datatemplate

#wpf #xaml #просмотр дерева #табличка данных

Вопрос:

Я пытаюсь настроить функциональность «развернуть при выборе» для TreeViewItem определенного типа, как показано ниже:

 <UserControl x:Class="ImprovedDirectory.Views.DirectoryView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:local="clr-namespace:ImprovedDirectory.Views"
         xmlns:vms="clr-namespace:ImprovedDirectory.ViewModels"
         mc:Ignorable="d" 
         d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
        <DataTemplate x:Key="CollapsedItem" DataType="{x:Type vms:DirectoryItemViewModel}">
            <TextBlock 
                Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"
                VerticalAlignment="Center"
                Margin="5"/>
        </DataTemplate>
        <DataTemplate x:Key="ExpandedItem" DataType="{x:Type vms:DirectoryItemViewModel}">
            <StackPanel DataContext="{Binding}">
                <TextBlock 
                    Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"
                    VerticalAlignment="Center"
                    Margin="5"
                    Grid.Row="0"/>
                <TextBlock
                    Text="{Binding Number, UpdateSourceTrigger=PropertyChanged}"
                    VerticalAlignment="Center"
                    Margin="2.5"
                    Grid.Row="1"/>
                <TextBlock
                    Text="{Binding Email, UpdateSourceTrigger=PropertyChanged}"
                    VerticalAlignment="Center"
                    Margin="2.5"
                    Grid.Row="2"/>
            </StackPanel>
        </DataTemplate>
</UserControl.Resources>
<TreeView x:Name="DirectoryTreeView" ItemsSource="{Binding Groups}">
    <TreeView.Resources>
        <HierarchicalDataTemplate DataType="{x:Type vms:DirectoryGroupViewModel}" ItemsSource="{Binding Items, UpdateSourceTrigger=PropertyChanged}">
            <TextBlock 
                Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"
                VerticalAlignment="Center"
                Margin="5"/>
        </HierarchicalDataTemplate>
        <Style TargetType="{x:Type TreeViewItem}">
            <Style.Setters>
                <Setter Property="ItemTemplate" Value="{StaticResource CollapsedItem}"/>
            </Style.Setters>
            <Style.Triggers>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="ItemTemplate" Value="{StaticResource ExpandedItem}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
    </TreeView.Resources>
</TreeView>
  

Вывод выше выглядит следующим образом, и я понятия не имею, почему:
Пример вывода 1

Вот как это должно выглядеть, когда ничего не выбрано: Пример вывода 2

Я знаю, что это что-то действительно простое, чего мне не хватает с привязками. Однако на данный момент я действительно не уверен, я протестировал каждый DataTemplate элемент в UserControl.Resources по отдельности, и они оба работают так, как задумано.

У меня также возникла проблема, которая, казалось бы, связана с Style перезаписью форматирования для группы, а также только для элемента, поэтому я предполагаю, что второй вопрос будет касаться того, как я могу определить, какой конкретный DataType вывод выполняется для элементов, а не для всех объектов.

Будем признательны за любую помощь.

Ответ №1:

Вывод, который вы видите, обусловлен тем фактом, что вы установили DataTemplate as ItemTemplate в своем TreeViewItem стиле, который не имеет представления иерархии, например, ItemsSource для дочерних элементов.

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

Вместо замены шаблонов данных вы можете достичь желаемого результата более простым способом, просто объединив оба шаблона в один и отреагировав на IsSelected свойство в триггере, которое изменяет видимость элементов управления, которые скрыты, когда они не выбраны.

 <TreeView x:Name="DirectoryTreeView"
          ItemsSource="{Binding Groups}">
   <TreeView.ItemTemplate>
      <HierarchicalDataTemplate DataType="{x:Type vms:DirectoryGroupViewModel}" 
                                ItemsSource="{Binding Items}">
         <StackPanel>
            <TextBlock Text="{Binding Name}"
                       VerticalAlignment="Center"
                       Margin="5"/>
            <TextBlock x:Name="NumberTextBlock"
                       Text="{Binding Number}"
                       VerticalAlignment="Center"
                       Margin="2.5"
                       Visibility="Collapsed"/>
            <TextBlock x:Name="EmailTextBlock"
                       Text="{Binding Email}"
                       VerticalAlignment="Center"
                       Margin="2.5"
                       Visibility="Collapsed"/>
         </StackPanel>
         <HierarchicalDataTemplate.Triggers>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}}, Path=IsSelected}" Value="True">
               <Setter TargetName="NumberTextBlock" Property="Visibility" Value="Visible"/>
               <Setter TargetName="EmailTextBlock" Property="Visibility" Value="Visible"/>
            </DataTrigger>
         </HierarchicalDataTemplate.Triggers>
      </HierarchicalDataTemplate>
   </TreeView.ItemTemplate>
</TreeView>
  

Вместо триггеров вы также можете использовать a BooleanToVisibilityConverter для привязки Visibility напрямую.

 <TreeView x:Name="DirectoryTreeView"
          ItemsSource="{Binding Groups}">
   <TreeView.Resources>
      <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
   </TreeView.Resources>
   <TreeView.ItemTemplate>
      <HierarchicalDataTemplate DataType="{x:Type vms:DirectoryGroupViewModel}" 
                                ItemsSource="{Binding Items}">
         <StackPanel>
            <TextBlock Text="{Binding Name}"
                       VerticalAlignment="Center"
                       Margin="5"/>
            <TextBlock Text="{Binding Number}"
                       VerticalAlignment="Center"
                       Margin="2.5"
                       Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}}, Path=IsSelected, Converter={StaticResource BooleanToVisibilityConverter}}"/>
            <TextBlock Text="{Binding Email}"
                       VerticalAlignment="Center"
                       Margin="2.5"
                       Visibility="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeViewItem}}, Path=IsSelected, Converter={StaticResource BooleanToVisibilityConverter}}"/>
         </StackPanel>
      </HierarchicalDataTemplate>
   </TreeView.ItemTemplate>
</TreeView>