如何用WPF实现类似任务管理器的树形列表样式?
WPF实现任务管理器风格树形列表的方案
针对你需要的任务管理器风格树形列表(嵌套子进程、整行悬停高亮、列对齐、保留折叠箭头),结合.NET 4.7.1的限制,给你几个关键实现方向和具体代码参考:
1. 重写TreeViewItem模板,解决整行拉伸与高亮问题
你之前设置HorizontalContentAlignment="Stretch"没生效,是因为默认TreeViewItem的ControlTemplate里,内容容器(Border、ContentPresenter)没有继承拉伸属性,必须重写模板才能让内容占满整个TreeView宽度,同时添加悬停高亮逻辑:
<!-- 自定义TreeViewItem样式 --> <Style x:Key="ProcessTreeViewItemStyle" TargetType="{x:Type TreeViewItem}"> <Setter Property="HorizontalContentAlignment" Value="Stretch"/> <Setter Property="VerticalContentAlignment" Value="Center"/> <Setter Property="Height" Value="28"/> <!-- 统一行高,和任务管理器一致 --> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type TreeViewItem}"> <Grid HorizontalAlignment="Stretch"> <!-- 展开/折叠箭头 --> <ToggleButton x:Name="Expander" Style="{StaticResource ExpandCollapseToggleStyle}" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press" Margin="0,0,5,0"/> <!-- 内容容器,负责整行高亮 --> <Border x:Name="ItemBorder" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="0" HorizontalAlignment="Stretch" Margin="20,0,0,0"> <!-- 缩进,对应箭头宽度 --> <ContentPresenter x:Name="HeaderPresenter" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" SnapsToDevicePixels="True"/> </Border> <!-- 子项容器 --> <ItemsPresenter x:Name="ChildItemsHost" Margin="20,0,0,0" Visibility="Collapsed"/> </Grid> <ControlTemplate.Triggers> <!-- 展开/折叠显示子项 --> <Trigger Property="IsExpanded" Value="True"> <Setter TargetName="ChildItemsHost" Property="Visibility" Value="Visible"/> </Trigger> <!-- 鼠标悬停整行高亮 --> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="ItemBorder" Property="Background" Value="#FFE0F0FF"/> </Trigger> <!-- 选中状态样式(可选) --> <Trigger Property="IsSelected" Value="True"> <Setter TargetName="ItemBorder" Property="Background" Value="#FFCCE5FF"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <!-- 自定义展开/折叠箭头样式 --> <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}"> <Grid Width="16" Height="16" Background="Transparent"> <Path x:Name="ArrowPath" Data="M0,4 L8,4 L8,0 L12,6 L8,12 L8,8 L0,8 Z" Fill="#666" HorizontalAlignment="Center" VerticalAlignment="Center"/> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsChecked" Value="True"> <Setter TargetName="ArrowPath" Property="Data" Value="M0,6 L6,6 L6,0 L12,6 L6,12 L6,6 L0,6 Z"/> </Trigger> <Trigger Property="IsMouseOver" Value="True"> <Setter TargetName="ArrowPath" Property="Fill" Value="#000"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>
2. 构建列对齐的树形项布局
TreeView本身没有表头,所以需要单独做一个表头Grid,和每个TreeViewItem里的内容Grid使用相同的列宽设置,确保表头与内容对齐。如果需要支持动态调整列宽,可以用SharedSizeGroup绑定列:
<!-- 表头区域 --> <Grid Margin="0,0,0,6"> <Grid.ColumnDefinitions> <ColumnDefinition Width="220" SharedSizeGroup="ProcessNameCol"/> <ColumnDefinition Width="100" SharedSizeGroup="PIDCol"/> <ColumnDefinition Width="180" SharedSizeGroup="MemoryCol"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Grid.Column="0" Text="进程名称" FontWeight="Bold" Margin="25,2,0,2"/> <!-- 留箭头位置的缩进 --> <TextBlock Grid.Column="1" Text="PID" FontWeight="Bold" Margin="0,2,5,2" HorizontalAlignment="Right"/> <TextBlock Grid.Column="2" Text="内存使用" FontWeight="Bold" Margin="0,2,5,2" HorizontalAlignment="Right"/> </Grid> <!-- 树形列表区域 --> <TreeView ItemsSource="{Binding RootProcesses}" ItemContainerStyle="{StaticResource ProcessTreeViewItemStyle}" Background="White" BorderThickness="0"> <TreeView.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding ChildProcesses}"> <!-- 每个树形项的内容Grid,列与表头完全对应 --> <Grid HorizontalAlignment="Stretch"> <Grid.ColumnDefinitions> <ColumnDefinition SharedSizeGroup="ProcessNameCol"/> <ColumnDefinition SharedSizeGroup="PIDCol"/> <ColumnDefinition SharedSizeGroup="MemoryCol"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <TextBlock Grid.Column="0" Text="{Binding Name}" Margin="5,2"/> <TextBlock Grid.Column="1" Text="{Binding Id}" Margin="0,2,5,2" HorizontalAlignment="Right"/> <TextBlock Grid.Column="2" Text="{Binding MemoryUsage}" Margin="0,2,5,2" HorizontalAlignment="Right"/> </Grid> </HierarchicalDataTemplate> </TreeView.ItemTemplate> </TreeView>
3. 关键注意事项
- 列对齐:使用
SharedSizeGroup可以让表头和内容的列自动同步宽度,即使调整窗口大小也能保持对齐;如果不需要动态同步,直接设置固定宽度也可以。 - 缩进控制:TreeViewItem模板里的
Margin="20,0,0,0"是子项的缩进量,和箭头的宽度匹配,确保树形结构整齐。 - .NET 4.7.1兼容性:所有用到的XAML特性(ControlTemplate、HierarchicalDataTemplate、SharedSizeGroup)在.NET 4.7.1中都完全支持,不需要额外依赖。
- 数据结构:你的ViewModel需要包含树形结构,比如一个
ProcessViewModel类,包含Name、Id、MemoryUsage属性,以及ChildProcesses集合属性。
内容的提问来源于stack exchange,提问作者Devak Nanda
相关产品推荐
相关产品推荐

