2013-05-10 3 views
8

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

enter image description here

Следующий код, что я до сих пор.

<HierarchicalDataTemplate DataType="{x:Type model:Node}" ItemsSource="{Binding Children, Mode=OneWay}"> 
    <StackPanel> 
      <TextBlock Text="{Binding Name}"/> 
    </StackPanel> 
    <HierarchicalDataTemplate.ItemContainerStyle> 
      <Style TargetType="{x:Type TreeViewItem}"> 
       //what goes in here??? 
      </Style> 
    </HierarchicalDataTemplate.ItemContainerStyle>  
</HierarchicalDataTemplate> 

Что нужно добавить для реализации моей границы так, как я хочу?

ответ

12

Оказывать Border вокруг сбора детей для TreeViewItem нам нужно изменить Style для ItemContainerStyle в TreeView

StyleTreeViewItem по умолчанию использует <ItemsPresenter x:Name="ItemsHost" />, чтобы сделать это детское содержание. Содержание

Детская в стандартном ItemContainerStyle дается

<ItemsPresenter x:Name="ItemsHost" 
       Grid.Row="1" 
       Grid.Column="1" 
       Grid.ColumnSpan="2" /> 

Теперь, чтобы проверить это, я имел коллекцию с BOOL именем Type и просто пытался вынести Border когда BOOL был Правда

Итак, я обновил ItemsPresenter до

<Border Grid.Row="1" 
     Grid.Column="1" 
     Grid.ColumnSpan="2" 
     BorderThickness="1"> 
    <Border.Style> 
    <Style TargetType="{x:Type Border}"> 
     <Setter Property="BorderBrush" 
       Value="Transparent" /> 
     <Style.Triggers> 
     <DataTrigger Binding="{Binding RelativeSource={RelativeSource FindAncestor, 
             AncestorType={x:Type TreeViewItem}}, 
             Path=DataContext.Type}" 
         Value="True"> 
      <Setter Property="BorderBrush" 
        Value="Red" /> 
     </DataTrigger> 
     </Style.Triggers> 
    </Style> 
    </Border.Style> 
    <ItemsPresenter x:Name="ItemsHost" /> 
</Border> 

Который затем вынес следующее

enter image description here

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

В моем случае переменной Type было установлено значение Истина для элемента с «1.1», так как это содержимое заголовка.

+0

Я попытаюсь свое решение в понедельник, когда я вернусь к работе. Спасибо за ответ –

+0

Ваше решение помещает границу вокруг каждого отдельного TreeViewItem.Мне нужна граница вокруг всех групп TreeviewItems –

+0

@Kazuo ye перед тем, как опубликовать это изображение, я понял ваш вопрос о наличии границы вокруг каждого элемента. Я обновил свой ответ, чтобы воспроизвести опубликованное изображение. Надеюсь, что поможет – Viv

2

Похоже, команда WPF подумал, что никто не будет нужна эта функция, чтобы они не включили ни границы вокруг ItemsPresenter в TreeViewItem шаблоне, так что вы будете иметь, чтобы изменить TreeViewItem шаблон и добавить рамку вокруг ItemsPresenter.

Вы можете просматривать по умолчанию TreeViewItem стиль/определение шаблона путем загрузки тем для XFL темы WPF. Ссылки предоставлены here.

Вот полный XAML рабочего раствора:

<Window x:Class="WpfApplication.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:model="clr-namespace:WpfApplication"> 

    <Window.DataContext> 
     <x:ArrayExtension Type="{x:Type model:Node}"> 
      <model:Node Name="Root"> 
       <model:Node.Children> 
        <model:Node Name="Child 1" HasChildrenBorder="True"> 
         <model:Node.Children> 
          <model:Node Name="Child 1.1"/> 
          <model:Node Name="Child 1.2"/> 
          <model:Node Name="Child 1.3"/> 
         </model:Node.Children> 
        </model:Node> 
        <model:Node Name="Child 2"/> 
       </model:Node.Children> 
      </model:Node> 
     </x:ArrayExtension> 
    </Window.DataContext> 

    <TreeView ItemsSource="{Binding}"> 

     <TreeView.Resources> 

      <!--This part is extracted from Areo.NormalColor.xaml WPF Theme which you can download from locations explained here: https://stackoverflow.com/questions/4158678/where-can-i-download-microsofts-standard-wpf-themes-from/4158681#4158681--> 
      <PathGeometry x:Key="TreeArrow"> 
       <PathGeometry.Figures> 
        <PathFigureCollection> 
         <PathFigure IsFilled="True" 
            StartPoint="0 0" 
            IsClosed="True"> 
          <PathFigure.Segments> 
           <PathSegmentCollection> 
            <LineSegment Point="0 6"/> 
            <LineSegment Point="6 0"/> 
           </PathSegmentCollection> 
          </PathFigure.Segments> 
         </PathFigure> 
        </PathFigureCollection> 
       </PathGeometry.Figures> 
      </PathGeometry> 

      <Style x:Key="ExpandCollapseToggleStyle" TargetType="{x:Type ToggleButton}"> 
       <Setter Property="Focusable" Value="False"/> 
       <Setter Property="Width" Value="16"/> 
       <Setter Property="Height" Value="16"/> 
       <Setter Property="Template"> 
        <Setter.Value> 
         <ControlTemplate TargetType="{x:Type ToggleButton}"> 
          <Border Width="16" 
            Height="16" 
            Background="Transparent" 
            Padding="5,5,5,5"> 
           <Path x:Name="ExpandPath" 
             Fill="Transparent" 
             Stroke="#FF989898" 
             Data="{StaticResource TreeArrow}"> 
            <Path.RenderTransform> 
             <RotateTransform 
              Angle="135" 
              CenterX="3" 
              CenterY="3"/> 
            </Path.RenderTransform> 
           </Path> 
          </Border> 
          <ControlTemplate.Triggers> 
           <Trigger Property="IsMouseOver" Value="True"> 
            <Setter TargetName="ExpandPath" Property="Stroke" Value="#FF1BBBFA"/> 
            <Setter TargetName="ExpandPath" Property="Fill" Value="Transparent"/> 
           </Trigger> 
           <Trigger Property="IsChecked" Value="True"> 
            <Setter TargetName="ExpandPath" Property="RenderTransform"> 
             <Setter.Value> 
              <RotateTransform 
               Angle="180" 
               CenterX="3" 
               CenterY="3"/> 
             </Setter.Value> 
            </Setter> 
            <Setter TargetName="ExpandPath" Property="Fill" Value="#FF595959"/> 
            <Setter TargetName="ExpandPath" Property="Stroke" Value="#FF262626"/> 
           </Trigger> 
          </ControlTemplate.Triggers> 
         </ControlTemplate> 
        </Setter.Value> 
       </Setter> 
      </Style> 

      <Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource {x:Type TreeViewItem}}"> 
       <Setter Property="Template"> 
        <Setter.Value> 
         <ControlTemplate TargetType="{x:Type TreeViewItem}"> 
          <Grid> 
           <Grid.ColumnDefinitions> 
            <ColumnDefinition MinWidth="19" Width="Auto"/> 
            <ColumnDefinition Width="Auto"/> 
            <ColumnDefinition Width="Auto"/> 
           </Grid.ColumnDefinitions> 
           <Grid.RowDefinitions> 
            <RowDefinition Height="Auto"/> 
            <RowDefinition/> 
           </Grid.RowDefinitions> 
           <ToggleButton x:Name="Expander" 
               Style="{StaticResource ExpandCollapseToggleStyle}" 
               IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" 
               ClickMode="Press"/> 
           <Border Name="Bd" 
             Grid.Column="1" 
             Background="{TemplateBinding Background}" 
             BorderBrush="{TemplateBinding BorderBrush}" 
             BorderThickness="{TemplateBinding BorderThickness}" 
             Padding="{TemplateBinding Padding}" 
             SnapsToDevicePixels="True"> 
            <ContentPresenter x:Name="PART_Header" 
                 ContentSource="Header" 
                 HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                 SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/> 
           </Border> 
           <Border Name="ItemsHostBd" 
             Grid.Row="1" 
             Grid.Column="1" 
             Grid.ColumnSpan="2"> 
            <ItemsPresenter x:Name="ItemsHost"/> 
           </Border> 
          </Grid> 
          <ControlTemplate.Triggers> 
           <Trigger Property="IsExpanded" Value="False"> 
            <Setter TargetName="ItemsHostBd" Property="Visibility" Value="Collapsed"/> 
           </Trigger> 
           <Trigger Property="HasItems" Value="False"> 
            <Setter TargetName="Expander" Property="Visibility" Value="Hidden"/> 
           </Trigger> 
           <Trigger Property="IsSelected" Value="True"> 
            <Setter TargetName="Bd" Property="Background" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/> 
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/> 
           </Trigger> 
           <MultiTrigger> 
            <MultiTrigger.Conditions> 
             <Condition Property="IsSelected" Value="True"/> 
             <Condition Property="IsSelectionActive" Value="False"/> 
            </MultiTrigger.Conditions> 
            <Setter TargetName="Bd" Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/> 
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/> 
           </MultiTrigger> 
           <Trigger Property="IsEnabled" Value="False"> 
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/> 
           </Trigger> 

           <!-- This part is customized to work with HasChildrenBorder property from data-bound object. --> 
           <DataTrigger Binding="{Binding HasChildrenBorder}" Value="True"> 
            <Setter TargetName="ItemsHostBd" Property="BorderBrush" Value="Red"/> 
            <Setter TargetName="ItemsHostBd" Property="BorderThickness" Value="1"/> 
           </DataTrigger> 

          </ControlTemplate.Triggers> 
         </ControlTemplate> 
        </Setter.Value> 
       </Setter> 
      </Style> 

      <HierarchicalDataTemplate DataType="{x:Type model:Node}" ItemsSource="{Binding Children}"> 
       <TextBlock Text="{Binding Name}"/> 
      </HierarchicalDataTemplate> 

     </TreeView.Resources> 

    </TreeView> 
</Window> 

Вот как определяется класс Node:

using System.Collections.ObjectModel; 

namespace WpfApplication 
{ 
    public class Node 
    { 
     public string Name { get; set; } 
     public ObservableCollection<Node> Children { get; set; } 

     public bool HasChildrenBorder { get; set; } 

     public Node() 
     { 
      this.Children = new ObservableCollection<Node>(); 
     } 
    } 
} 
+0

Спасибо за ответ, но я не хочу, чтобы мои занятия содержат любые данные о том, как они должны быть представлены в пользовательском интерфейсе. Лучшим решением в моем случае будет только xaml. –

+0

Свойство HasChildrenBorder использовалось как пример, чтобы показать, что концепция работает. Вы можете поместить там любое другое свойство, для которого дети TreeViewItem должны быть ограничены. Затем вы должны просто изменить DataTrigger.Binding в ControlTemplate TreeViewItem. – Stipo

+0

А, моя ошибка. Спасибо за ответ. Я нашел решение своей проблемы с помощью другого плаката. –

Смежные вопросы