如何在C# WPF层级TreeView中添加作物年份额外层级?
在WPF TreeView中添加年份层级的实现方案
我来帮你搞定这个TreeView加年份层级的需求,其实核心是数据分组+模板适配,一步步来:
1. 新增中间层级的数据模型
首先我们需要一个承载年份和对应Crop集合的中间节点类,用来作为Field和Crop之间的层级:
public class YearNode { // 年份值(如果有未指定年份的情况,可以加DisplayName属性优化显示) public int Year { get; set; } // 该年份对应的所有Crop public IEnumerable<Crop> Items { get; set; } // 可选:处理未指定年份的友好显示 public string DisplayName => Year == 0 ? "未指定年份" : Year.ToString(); }
2. 给Field类添加分组后的年份集合属性
接下来要把Field原有的Crop集合按年份分组,生成YearNode的集合。如果你用的是MVVM,也可以在ViewModel里处理这个逻辑:
public class Field { // 原有属性,比如FieldName、原Crop集合Items public string FieldName { get; set; } public IEnumerable<Crop> Items { get; set; } // 新增:按CropYear分组后的年份节点集合 public IEnumerable<YearNode> YearGroups { get { if (Items == null) return Enumerable.Empty<YearNode>(); // 分组逻辑:处理可能的null年份,按年份排序 return Items .GroupBy(crop => crop.CropYear.HasValue ? crop.CropYear.Value.Year : 0) .OrderBy(group => group.Key) .Select(group => new YearNode { Year = group.Key, Items = group.OrderBy(crop => crop.CropName) // 可选:给Crop加个排序 }); } } }
注意:如果你的Crop集合是动态变化的(比如增删Crop),记得让Field实现
INotifyPropertyChanged,在Items变化时触发YearGroups的属性变更通知,或者把YearGroups改成ObservableCollection<YearNode>并在Items更新时重新生成集合。
3. 修改TreeView的XAML模板
现在要更新TreeView的资源,新增YearNode的模板,同时把Field的ItemsSource从原Crop集合改成YearGroups:
<TreeView x:Name="tvFields" Margin="10" HorizontalContentAlignment="Stretch"> <TreeView.Resources> <!-- 年份节点模板:显示年份+该年份的Crop数量 --> <HierarchicalDataTemplate DataType="{x:Type local:YearNode}" ItemsSource="{Binding Items}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding DisplayName}" FontWeight="Bold" Margin="0 0 5 0"/> <TextBlock Text="($" Foreground="Gray"/> <TextBlock Text="{Binding Items.Count()}" Foreground="Gray"/> <TextBlock Text=")" Foreground="Gray"/> </StackPanel> </HierarchicalDataTemplate> <!-- Field节点模板:修改ItemsSource为YearGroups --> <HierarchicalDataTemplate DataType="{x:Type entites:Field}" ItemsSource="{Binding YearGroups}"> <StackPanel Orientation="Horizontal" Background="LightBlue"> <TextBlock Text="{Binding FieldName}" Margin="5"/> <!-- 保留你原来Field的其他UI元素 --> </StackPanel> </HierarchicalDataTemplate> <!-- 原有Crop模板保持不变,它的子项还是Fertilizer、Pesticide等 --> <HierarchicalDataTemplate DataType="{x:Type entites:Crop}" ItemsSource="{Binding Items}"> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding CropName}" Margin="5"/> <TextBlock Text="(" Foreground="Gray"/> <TextBlock Text="{Binding CropYear, StringFormat='yyyy'}" Foreground="Gray"/> <TextBlock Text=")" Foreground="Gray"/> </StackPanel> </HierarchicalDataTemplate> <!-- 保留你原来的Fertilizer、Pesticide等模板 --> <DataTemplate DataType="{x:Type entites:Fertilizer}"> <TextBlock Text="{Binding FertilizerName}" Margin="10 0"/> </DataTemplate> <DataTemplate DataType="{x:Type entites:Pesticide}"> <TextBlock Text="{Binding PesticideName}" Margin="10 0"/> </DataTemplate> </TreeView.Resources> </TreeView>
4. 最终效果
这样你的TreeView结构就变成了:
- Field
- 2017 (3)
- Crop A (2017)
- Fertilizer X
- Pesticide Y
- Crop B (2017)
- ...
- Crop A (2017)
- 2018 (2)
- Crop C (2018)
- ...
- Crop C (2018)
- 未指定年份 (1)
- Crop D
- ...
- Crop D
- 2017 (3)
内容的提问来源于stack exchange,提问作者Lyror
相关产品推荐
相关产品推荐

