自定义TreeView样式结果,实现类似VS的资源管理器折叠菜单效果
效果
注意:文件夹图标根据折叠情况变换,上图展示的图标使用了Icon也可以使用Image控制
关于Icon资源可以翻看前面的文章有介绍使用
思路
1:重定义TreeView的数据模板(HierarchicalDataTemplate) —— 能够帮助层级控件显示层级数据的模板是HierarchicalDataTemplate
2:重定义TreeViewItem的样式模板,绑定对应的数据内容(可根据自身数据需求处理)
3:模板中定义事件监控折叠开关,通过事件调整不同展示状态下的效果功能
xaml
<UserControl x:Class="Wpf.AvalonDock.UserControls.TestTreeView"
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:BbFrame="clr-namespace:Wpf.AvalonDock.UserControls"
xmlns:local="clr-namespace:Wpf.AvalonDock.UserControls"
mc:Ignorable="d" x:Name="My_TV">
<UserControl.Resources>
<Style x:Key="TreeViewItemFocusVisual">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate>
<Rectangle/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Checked.Fill" Color="#FF595959"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Checked.Stroke" Color="#FF262626"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Stroke" Color="#FF27C7F7"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Fill" Color="#FFCCEEFB"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Checked.Stroke" Color="#FF1CC4F7"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.MouseOver.Checked.Fill" Color="#FF82DFFB"/>
<PathGeometry x:Key="TreeArrow" Figures="M0,0 L0,6 L6,0 z"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Fill" Color="#FFFFFFFF"/>
<SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Stroke" Color="#FF818181"/>
<SolidColorBrush x:Key="TreeViewItemCheck_True" Color="#FF27C7F7" Opacity="0.3"/>
<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 Background="Transparent" Height="16" Padding="5,5,5,5" Width="16">
<Path x:Name="ExpandPath" Data="{StaticResource TreeArrow}" Fill="{StaticResource TreeViewItem.TreeArrow.Static.Fill}" Stroke="{StaticResource TreeViewItem.TreeArrow.Static.Stroke}">
<Path.RenderTransform>
<RotateTransform Angle="135" CenterY="3" CenterX="3"/>
</Path.RenderTransform>
</Path>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="True">
<Setter Property="RenderTransform" TargetName="ExpandPath">
<Setter.Value>
<RotateTransform Angle="180" CenterY="3" CenterX="3"/>
</Setter.Value>
</Setter>
<Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.Static.Checked.Fill}"/>
<Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.Static.Checked.Stroke}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Stroke}"/>
<Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Fill}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsChecked" Value="True"/>
</MultiTrigger.Conditions>
<Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Checked.Stroke}"/>
<Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Checked.Fill}"/>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="Background" Value="Transparent"/>
<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="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TreeViewItem}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition MinWidth="19" Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<ToggleButton x:Name="Expander" ClickMode="Press" PreviewMouseDown="ProductListItem_DoubleClick" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}"/>
<Border x:Name="Bd" Grid.Column="1" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
<!--<ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>-->
<StackPanel x:Name="CBbPropertyNodeName" Tag="{Binding CBbFrameType}" Width="{Binding ElementName=My_TV, Path=Width}"
HorizontalAlignment="Left" VerticalAlignment="Center"
Orientation="Horizontal" ContextMenu="{Binding m_contextMenu}">
<!--<Image VerticalAlignment="Center" Source="{Binding Image, Mode=TwoWay}" Width="16" Height="16"/>-->
<TextBlock x:Name="My_Icon" FontSize="18" Foreground="#558CDD"
Text="{Binding Icon, Mode=TwoWay}" Margin="2"
FontFamily="pack://application:,,,/Wpf.AvalonDock;component/Font/#icomoon"/>
<TextBlock x:Name="CBbPropertyNodeTName" VerticalAlignment="Center" HorizontalAlignment="Center"
Height="25" Padding="5"
Text="{Binding m_strName, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
</StackPanel>
</Border>
<ItemsPresenter x:Name="ItemsHost" Grid.Row="1" Grid.Column="1"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsExpanded" Value="false">
<Setter Property="Visibility" TargetName="ItemsHost" Value="Collapsed"/>
</Trigger>
<Trigger Property="HasItems" Value="false">
<Setter Property="Visibility" TargetName="Expander" Value="Hidden"/>
</Trigger>
<Trigger Property="IsSelected" Value="true">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource TreeViewItemCheck_True}"/>
<Setter Property="Foreground" Value="Black"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="Background" TargetName="Bd" Value="Transparent"/>
<Setter Property="Foreground" Value="Black"/>
</MultiTrigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="Gray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<EventSetter Event="MouseDoubleClick" Handler="ProductListItem_DoubleClick"/>
<!--<Style.Triggers>
<Trigger Property="VirtualizingPanel.IsVirtualizing" Value="true">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>-->
</Style>
</UserControl.Resources>
<TreeView Name="TView" BorderThickness="0">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type BbFrame:CBbPropertyNodeItem}" ItemsSource="{Binding Path=Children}">
<!--<StackPanel x:Name="CBbPropertyNodeName" Tag="{Binding CBbFrameType}" Width="{Binding ElementName=My_TV, Path=Width}"
HorizontalAlignment="Center" VerticalAlignment="Center" Background="Red"
PreviewMouseLeftButtonDown="CBbPropertyNodeName_PreviewMouseLeftButtonDown"
Orientation="Horizontal" ContextMenu="{Binding m_contextMenu}">
<Image VerticalAlignment="Center" Source="{Binding Icon}" Width="16" Height="16"/>
<TextBlock x:Name="CBbPropertyNodeTName" VerticalAlignment="Center" HorizontalAlignment="Center"
Height="25" Padding="5"
Text="{Binding m_strName, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
</StackPanel>-->
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</UserControl>
cs
public partial class TestTreeView : UserControl
{
public ObservableCollection<CBbPropertyNodeItem> itemList { get; set; }
= new ObservableCollection<CBbPropertyNodeItem>();
public TestTreeView()
{
InitializeComponent();
List<string> list = new List<string>();
for (int i = 1; i < 100; i++)
{
list.Add(String.Format("Test {0}", i));
}
//My_TreeView.ItemsSource = list;
CBbPropertyNodeItem cBbPropertyNodeItem1 = new CBbPropertyNodeItem()
{
Icon = "\ued96",
Image = "/Images/folder-close.png",
m_strName ="Test 1",
Children = new ObservableCollection<CBbPropertyNodeItem>()
{
new CBbPropertyNodeItem()
{
Icon = "\ued96",
Image = "/Images/folder-close.png",
m_strName ="Test 1_1",
},
new CBbPropertyNodeItem()
{
Icon = "\ued96",
Image = "/Images/folder-close.png",
m_strName ="Test 1_2",
},
new CBbPropertyNodeItem()
{
Icon = "\ued96",
Image = "/Images/folder-close.png",
m_strName ="Test 1_3",
}
}
};
CBbPropertyNodeItem cBbPropertyNodeItem2 = new CBbPropertyNodeItem()
{
Icon = "\ued96",
Image = "/Images/folder-close.png",
m_strName = "Test 2",
Children = new ObservableCollection<CBbPropertyNodeItem>()
{
new CBbPropertyNodeItem()
{
Icon = "\ued96",
Image = "/Images/folder-close.png",
m_strName ="Test 2_1",
},
new CBbPropertyNodeItem()
{
Icon = "\ued96",
Image = "/Images/folder-close.png",
m_strName ="Test 2_2",
},
new CBbPropertyNodeItem()
{
Icon = "\ued96",
Image = "/Images/folder-close.png",
m_strName ="Test 2_3",
}
}
};
itemList.Add(cBbPropertyNodeItem1);
itemList.Add(cBbPropertyNodeItem2);
this.TView.SetBinding(TreeView.ItemsSourceProperty, new Binding("itemList")
{
Source = this
});
}
private void ProductListItem_DoubleClick(object sender, MouseButtonEventArgs e)
{
TreeViewItem treeViewItem = sender as TreeViewItem;
ToggleButton toggleButton = sender as ToggleButton;
CBbPropertyNodeItem cBbPropertyNodeItem;
if (toggleButton != null)
{
cBbPropertyNodeItem = toggleButton.DataContext as CBbPropertyNodeItem;
cBbPropertyNodeItem.IsExpanded = toggleButton.IsChecked == false ? true : false;
}
else
{
cBbPropertyNodeItem = treeViewItem.Header as CBbPropertyNodeItem;
cBbPropertyNodeItem.IsExpanded = treeViewItem.IsExpanded == false ? true : false;
}
if (cBbPropertyNodeItem.IsExpanded)
{
cBbPropertyNodeItem.Image = "/Images/file-open.png";
cBbPropertyNodeItem.Icon = "\ued95";
}
else
{
cBbPropertyNodeItem.Image = "/Images/folder-close.png";
cBbPropertyNodeItem.Icon = "\ued96";
}
}
private void CBbPropertyNodeName_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
CBbPropertyNodeItem cBbPropertyNodeItem =((StackPanel)sender).DataContext as CBbPropertyNodeItem;
if (cBbPropertyNodeItem != null)
{
foreach (var item in itemList)
{
if ((CBbPropertyNodeItem)item== cBbPropertyNodeItem)
{
item.IsExpanded = item.IsExpanded == false ? true:false;
if (!item.IsExpanded)
{
foreach (var items in item.Children)
{
((CBbPropertyNodeItem)items).IsExpanded = false;
}
}
}
}
}
}
}
源码
https://download.csdn.net/download/qq_34581845/85945990