重写TreeView模板来实现数据分层展示

Posted Hello 寻梦者!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了重写TreeView模板来实现数据分层展示相关的知识,希望对你有一定的参考价值。

  前面一片文章实现TreeView的基本的模板重写,那么照着这个思路,我们再来写一个稍稍复杂的TreeView ,其它的内容都和前面系列内容相似,还是和之前文章介绍的一样,首先看看做出的DEMO的最终样式,先来一睹为快。

其实并不复杂,关键的是要准确去理解TreeView这个控件,这个控件的核心是TreeViewItem,那么我们就重点来看看这个样式该怎么写。

 <Style TargetType="{x:Type TreeViewItem}">
            <Setter Property="Background" Value="Transparent"/>           
            <!--此处设置TreeViewItem的绑定样式-->
            <Setter Property="IsExpanded" Value="True"></Setter>
            <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
            <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
            <Setter Property="Padding" Value="1,0,0,0"/>
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
            <Setter Property="FocusVisualStyle" Value="{StaticResource TreeViewItemFocusVisual}"/>   
            <Setter Property="ItemsPanel">
                <Setter.Value>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal" IsItemsHost="True" Margin="10"></StackPanel>
                    </ItemsPanelTemplate>                  
                </Setter.Value>
            </Setter>     
           
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type TreeViewItem}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" MinWidth="19"/>
                                <ColumnDefinition Width="*"/>
                                <ColumnDefinition Width="Auto"/>
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto" MinHeight="22"/>
                                <RowDefinition  Height="Auto"/>
                                <RowDefinition  Height="Auto"/>
                            </Grid.RowDefinitions>                          
                            <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" 
                                    BorderThickness="{TemplateBinding BorderThickness}" 
                                    Background="#00a3d9" 
                                    Grid.Row="0"
                                    Grid.Column="1" 
                                    Padding="{TemplateBinding Padding}" 
                                    SnapsToDevicePixels="true"
                                    MaxWidth="300"
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center">
                                <ContentPresenter x:Name="PART_Header" 
                                                  ContentSource="Header"
                                                  HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                            </Border>
                            <Rectangle x:Name="VerLn" Grid.Row="1" Grid.Column="1" Width="1" Stroke="Green" HorizontalAlignment="Center" VerticalAlignment="Stretch" Height="50" SnapsToDevicePixels="true" Fill="White"/>
                            <Border x:Name="itemsBorder" 
                                    BorderBrush="#00a3d9"
                                    BorderThickness="1"                                    
                                    Padding="2"
                                    Margin="10,0,10,0"
                                    Grid.ColumnSpan="3" 
                                    Grid.Column="0" 
                                    Grid.Row="2" 
                                    HorizontalAlignment="Center"
                                    VerticalAlignment="Center">
                                   <ItemsPresenter x:Name="ItemsHost" />
                            </Border>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsExpanded" Value="false">
                                <Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
                            </Trigger>
                            <Trigger Property="HasItems" Value="false">
                                <Setter Property="Height" TargetName="VerLn" Value="0"/>
                                <Setter Property="Height" TargetName="itemsBorder" Value="0"/>
                            </Trigger>                            
                            <Trigger Property="IsSelected" Value="true">
                                <Setter Property="Background" TargetName="Bd" 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 Property="Background" TargetName="Bd" 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>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
            <Style.Triggers>
                <Trigger Property="VirtualizingStackPanel.IsVirtualizing" Value="true">
                    <Setter Property="ItemsPanel">
                        <Setter.Value>
                            <ItemsPanelTemplate>
                                <VirtualizingStackPanel/>
                            </ItemsPanelTemplate>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </Style.Triggers>
        </Style>

  在这里我们把整个Grid分成了三行和三列,第0行第一列来来呈现我们每一个TreeViewItem的Header属性,我们让其居中显示,在第1行第一列我们来显示一条直线,这里我们也是用的Rectangle,当然使用Border和使用Path的效果其实是一样的,这个每个人习惯不同,最后面一行我们来显示ItemsPresenter,这个和上面一篇形式上是差不多的,我们就不详细介绍,这里需要重点注意的是下面的内容。

<Setter Property="ItemsPanel">
                <Setter.Value>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal" IsItemsHost="True" Margin="10"></StackPanel>
                    </ItemsPanelTemplate>                  
                </Setter.Value>
            </Setter>     

  即ItemsPresenter是放在一个容器中的,这个容器决定了里面的Item到底需要通过怎样的方式来呈现,这里我们是使用的是横向排列的StackPanel控件来作为父容器的,另外需要注意到这个常用的Trigger

  <Trigger Property="HasItems" Value="false">
                                <Setter Property="Height" TargetName="VerLn" Value="0"/>
                                <Setter Property="Height" TargetName="itemsBorder" Value="0"/>
                            </Trigger>                   

  这个在TreeView控件中是非常常用的,这里需要特别注意。

     接下里我们再看看当前的TreeView的具体数据绑定和其它的数据逻辑。

<TreeView Name="trvMenu" HorizontalContentAlignment="Center" VerticalContentAlignment="Center">            
            <TreeView.ItemTemplate>                
                <HierarchicalDataTemplate DataType="{x:Type self:MyTreeViewItem}" 
                                          ItemsSource="{Binding Children}">
                    <StackPanel Orientation="Horizontal" Margin="10">
                        <Ellipse x:Name="ellipse" Width="16" Height="16" Margin="2,0,2,0" Fill="Transparent">
                            <Ellipse.Triggers>
                                <EventTrigger  RoutedEvent="Loaded">
                                    <BeginStoryboard>
                                        <Storyboard  AutoReverse="True" RepeatBehavior="Forever">
                                            <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="ellipse">
                                                <EasingColorKeyFrame KeyTime="0:0:0.0" Value="Transparent"/>
                                                <EasingColorKeyFrame KeyTime="0:0:0.5" Value="DarkGreen"/>
                                            </ColorAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </EventTrigger>
                            </Ellipse.Triggers>
                        </Ellipse>
                        <Image x:Name="image"  
                               Source="/TestTreeView;component/Images/connect.png"
                               Margin="2,0,2,0"
                               Width="24" 
                               Height="24"
                               Stretch="Fill">                            
                        </Image>
                        <TextBlock Text="{Binding TreeViewItemName}" VerticalAlignment="Center" FontSize="16" Foreground="White" Margin="2,0,2,0"/>
                    </StackPanel>       
                    <HierarchicalDataTemplate.Triggers>
                        <DataTrigger Binding="{Binding NodeType}" Value="采集服务器">
                            <Setter Property="Source" TargetName="image" Value="/TestTreeView;component/Images/connect.png"></Setter>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding NodeType}" Value="控制服务器">
                            <Setter Property="Source" TargetName="image" Value="/TestTreeView;component/Images/medium_alarm_hit.png"></Setter>
                        </DataTrigger>
                    </HierarchicalDataTemplate.Triggers>
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>

  这里需要注意的是当前的TreeViewItem直接是作用在TreeView上的,如果TreeViewItem添加了x:Key属性,那么该如何引用该TreeViewItem样式呢?正确的方式是设置TreeView的ItemContainerStyle属性,这里需要注意,这篇文章就介绍到这里,如果能够与前面的一篇内容结合起来看,那么相信对TreeView控件会有更多的理解吧!

 

以上是关于重写TreeView模板来实现数据分层展示的主要内容,如果未能解决你的问题,请参考以下文章

Wpf Xaml - TreeView 分层数据模板 - 多个项目源

将多个分层数据模板分配给 TreeView ItemTemplate 的正确方法是啥?

WPF中TreeView控件数据绑定和后台动态添加数据

Windows 窗体 TreeView - 绑定分层递归数据源

wpf的TreeView和C#的实现节点方法的API有啥不同?

wpf 实现多个选项卡左右移动