WPF DataGrid如何通过代码绑定类中列表动态添加班次列?
解决WPF DataGrid动态绑定班次列的方案
嘿,这个动态生成DataGrid班次列的需求我熟,给你一步步讲怎么实现!
1. 优化Employee类(可选但推荐)
为了让数据变化能实时同步到UI,最好让Employee实现INotifyPropertyChanged接口;如果后续需要支持班次数量动态更新,也可以把List<int>换成ObservableCollection<int>:
using System.ComponentModel; using System.Runtime.CompilerServices; using System.Collections.Generic; public class Employee : INotifyPropertyChanged { private string _name; public string Name { get => _name; set { _name = value; OnPropertyChanged(); } } private string _surName; public string SurName { get => _surName; set { _surName = value; OnPropertyChanged(); } } private int _rest; public int Rest { get => _rest; set { _rest = value; OnPropertyChanged(); } } private int _worked; public int Worked { get => _worked; set { _worked = value; OnPropertyChanged(); } } private List<int> _perShift = new List<int>(); public List<int> PerShift { get => _perShift; set { _perShift = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
2. 动态生成DataGrid列的核心逻辑
在窗口加载完成后(或者ViewModel初始化时),我们需要先确定班次的总数量,再生成对应列并绑定到PerShift的索引位置。这里有两种确定班次数量的方式:
- 方式一:取所有员工
PerShift列表的最大长度(适合没有单独班次表的场景) - 方式二:直接从数据库查询总班次数量(更准确,适合有班次管理表的场景)
下面是方式一的代码示例(假设你已经有了填充好数据的员工集合):
private void Window_Loaded(object sender, RoutedEventArgs e) { // 模拟从数据库获取的员工数据 var employeeCollection = new ObservableCollection<Employee> { new Employee { Name = "张三", Worked = 22, Rest = 8, PerShift = new List<int> { 5, 6, 4 } }, new Employee { Name = "李四", Worked = 20, Rest = 10, PerShift = new List<int> { 3, 7 } } }; // 计算需要生成的班次列数量:取所有员工PerShift的最大长度 int maxShiftCount = employeeCollection.Max(emp => emp.PerShift.Count); // 先添加固定列:姓名、总出勤、休息天数 dataGrid.Columns.Add(new DataGridTextColumn { Header = "姓名", Binding = new Binding("Name") }); dataGrid.Columns.Add(new DataGridTextColumn { Header = "总出勤天数", Binding = new Binding("Worked") }); dataGrid.Columns.Add(new DataGridTextColumn { Header = "休息天数", Binding = new Binding("Rest") }); // 动态生成班次列 for (int i = 0; i < maxShiftCount; i++) { // 必须单独捕获循环变量,避免闭包导致所有列绑定到最后一个索引 int currentShiftIndex = i; dataGrid.Columns.Add(new DataGridTextColumn { Header = $"第{currentShiftIndex + 1}班", // 绑定到PerShift的对应索引,FallbackValue确保无数据时显示0 Binding = new Binding($"PerShift[{currentShiftIndex}]") { FallbackValue = 0, TargetNullValue = 0 } }); } // 设置DataGrid的数据源 dataGrid.ItemsSource = employeeCollection; }
3. 关键注意点
- 闭包陷阱:循环里一定要把
i赋值给局部变量currentShiftIndex,不然所有动态列都会绑定到最后一个索引值,这是WPF开发里很容易踩的坑。 - 空值处理:通过
FallbackValue和TargetNullValue设置默认值,避免某个员工没有该班次记录时UI显示空白。 - 数据同步:因为我们实现了
INotifyPropertyChanged,后续员工的班次数据发生变化时,UI会自动同步更新。
如果你的数据库里有单独的班次表,直接用班次表的记录数来生成列会更准确,只需要把maxShiftCount替换成从数据库查询到的总班次数量即可。
内容的提问来源于stack exchange,提问作者Axilleas Kar
相关产品推荐
相关产品推荐

