效果图
先上效果图,若是你想要的效果,可以继续看下面的代码,不想浪费大家的时间。

样式定义
此处定义TreeView的样式,参考自MSDN,稍作修改。
注意:在TreeViewItem控件模板定义中绑定一个数据(Level)以及一个值转换器(LevelToMarginConverter),具体定义见下部分。
<Style x:Key="ExpandCollapseToggleStyle" TargetType="ToggleButton">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
<Border Width="12" Height="14">
<Path x:Name="ExpandPath" HorizontalAlignment="Right" VerticalAlignment="Center"
Fill="Transparent" Stroke="#FFE6E6E6" Data="M 2 2 L 7 7 L 2 12 Z"/>
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsChecked" Value="False"/>
</MultiTrigger.Conditions>
<Setter Property="Stroke" TargetName="ExpandPath" Value="#FF1BBBFA"/>
</MultiTrigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="Data" TargetName="ExpandPath" Value="M 1 10 L 7 3 L 7 10 Z"/>
<Setter Property="Fill" TargetName="ExpandPath" Value="#FFE6E6E6"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsChecked" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Stroke" TargetName="ExpandPath" Value="#FF1BBBFA"/>
<Setter Property="Fill" TargetName="ExpandPath" Value="#FF1BBBFA"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="TreeViewItemFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Border>
<Rectangle Margin="0,0,0,0" StrokeThickness="5" Stroke="Black" StrokeDashArray="1 2" Opacity="0" Fill="Black"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ModernTreeViewItem" TargetType="{x:Type TreeViewItem}">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
<Setter Property="VerticalContentAlignment" Value="{Binding Path=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="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<Border Name="Bd" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
<Grid Margin="{Binding Level, Converter={StaticResource LevelToMarginConverter}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ToggleButton x:Name="Expander" Style="{StaticResource ExpandCollapseToggleStyle}" ClickMode="Press" HorizontalAlignment="Left"
IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}"/>
<ContentPresenter Grid.Column="1" Margin="8,0,0,0" x:Name="PART_Header" ContentSource="Header"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</Grid>
</Border>
<ItemsPresenter x:Name="ItemsHost" Grid.Row="1"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="false">
<Setter TargetName="ItemsHost" Property="Visibility" Value="Collapsed"/>
</Trigger>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="Expander" Property="Visibility" Value="Hidden"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="HasHeader" Value="false"/>
<Condition Property="Width" Value="Auto"/>
</MultiTrigger.Conditions>
<Setter TargetName="PART_Header" Property="MinWidth" Value="75"/>
</MultiTrigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="HasHeader" Value="false"/>
<Condition Property="Height" Value="Auto"/>
</MultiTrigger.Conditions>
<Setter TargetName="PART_Header" Property="MinHeight" Value="19"/>
</MultiTrigger>
<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>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
值转换器定义
此转换器主要用于根据子节点的级数计算每行内容的缩进,根节点级数为1,根节点的子节点级数为2,依次类推。
class LevelToMarginConverter : System.Windows.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
var level = (int)value;
return new System.Windows.Thickness(8 * level + 10 * (level - 1), 0, 0, 0);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
数据定义
此处定义的TreeView空间绑定的数据。
注意:在TreeNode类中定义了Level属性,用于指示当前节点的级数。
public class TreeViewData
{
private static TreeViewData _Data = null;
public static TreeViewData Data
{
get
{
if(_Data == null)
{
_Data = new TreeViewData();
var rn1 = new TreeNode() { Label = "Root A", Level = 1 };
rn1.ChildNodes.Add(new TreeNode() { Label = "Root A - Child 1", Level = 2 });
rn1.ChildNodes.Add(new TreeNode() { Label = "Root A - Child 2", Level = 2 });
rn1.ChildNodes.Add(new TreeNode() { Label = "Root A - Child 3", Level = 2 });
rn1.ChildNodes.Add(new TreeNode() { Label = "Root A - Child 4", Level = 2 });
rn1.ChildNodes.Add(new TreeNode() { Label = "Root A - Child 5", Level = 2 });
var rn2 = new TreeNode() { Label = "Root B", Level = 1 };
rn2.ChildNodes.Add(new TreeNode() { Label = "Root B - Child 1", Level = 2 });
var rn21 = new TreeNode() { Label = "Root B - Child 2", Level = 2 };
rn21.ChildNodes.Add(new TreeNode() { Label = "Root B - Child 2 - Child 1", Level = 3 });
rn21.ChildNodes.Add(new TreeNode() { Label = "Root B - Child 2 - Child 2", Level = 3 });
rn2.ChildNodes.Add(rn21);
rn2.ChildNodes.Add(new TreeNode() { Label = "Root B - Child 3", Level = 2 });
rn2.ChildNodes.Add(new TreeNode() { Label = "Root B - Child 4", Level = 2 });
rn2.ChildNodes.Add(new TreeNode() { Label = "Root B - Child 5", Level = 2 });
var rn3 = new TreeNode() { Label = "Root C", Level = 1 };
rn3.ChildNodes.Add(new TreeNode() { Label = "Root C - Child 1", Level = 2 });
rn3.ChildNodes.Add(new TreeNode() { Label = "Root C - Child 2", Level = 2 });
rn3.ChildNodes.Add(new TreeNode() { Label = "Root C - Child 3", Level = 2 });
rn3.ChildNodes.Add(new TreeNode() { Label = "Root C - Child 4", Level = 2 });
rn3.ChildNodes.Add(new TreeNode() { Label = "Root C - Child 5", Level = 2 });
_Data.RootNodes.Add(rn1);
_Data.RootNodes.Add(rn2);
_Data.RootNodes.Add(rn3);
}
return _Data;
}
}
private System.Collections.ObjectModel.ObservableCollection<TreeNode> _RootNodes = null;
public IList<TreeNode> RootNodes { get { return _RootNodes ?? (_RootNodes = new System.Collections.ObjectModel.ObservableCollection<TreeNode>()); } }
public class TreeNode
{
public string Label { get; set; }
public int Level { get; set; }
private System.Collections.ObjectModel.ObservableCollection<TreeNode> _ChildNodes = null;
public IList<TreeNode> ChildNodes { get { return _ChildNodes ?? (_ChildNodes = new System.Collections.ObjectModel.ObservableCollection<TreeNode>()); } }
}
}
应用样式
<TreeView ItemsSource="{Binding Source={x:Static data:TreeViewData.Data}, Path=RootNodes}"
HorizontalContentAlignment="Stretch" Background="#FF252526" Width="300" ItemContainerStyle="{StaticResource ModernTreeViewItem}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type data:TreeViewData+TreeNode}" ItemsSource="{Binding ChildNodes}">
<Grid Height="32">
<TextBlock Text="{Binding Label}" VerticalAlignment="Center" Foreground="#FFE6E6E6" FontSize="13"/>
</Grid>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
|