如何在WPF DataGrid中选择全部用户时自动添加对应列?
WPF DataGrid 动态生成用户工时列(单选/全选切换)
需求说明
开发一款支持用户添加的工时计算软件,工时窗口的ComboBox可选择单个用户或「全部用户」:
- 选择单个用户时,DataGrid仅显示该用户的工时列
- 选择「全部用户」时,DataGrid自动添加所有用户对应的工时列
当前使用的DataGrid XAML代码:
<DataGrid Name="DgEsportazione" AutoGenerateColumns="False" IsReadOnly="True" ItemsSource="{Binding OreDate, UpdateSourceTrigger=PropertyChanged}" BindingGroup="{Binding ListaUtenti}" Style="{StaticResource DataGridStyle1}"> <DataGrid.ItemContainerStyle> <Style TargetType="DataGridRow"> <Style.Triggers> <DataTrigger Binding="{Binding Key.DayOfWeek}" Value="Saturday"> <Setter Property="Background" Value="{StaticResource Background}" /> </DataTrigger> <DataTrigger Binding="{Binding Key.DayOfWeek}" Value="Sunday"> <Setter Property="Background" Value="{StaticResource Background}" /> </DataTrigger> </Style.Triggers> </Style> </DataGrid.ItemContainerStyle> <DataGrid.Columns> <DataGridTextColumn Width="*" MinWidth="100" Binding="{Binding Key, ConverterCulture='it-IT', StringFormat=dddd dd/MM}" Header="Date" IsReadOnly="True" /> <DataGridTextColumn Width="*" MinWidth="100" Binding="{Binding Value}" Header="Working Hours" IsReadOnly="True" /> </DataGrid.Columns> </DataGrid>
解决方案
要实现动态列切换,需从数据模型调整和ViewModel动态管理列集合两方面入手:
1. 调整数据模型
原OreDate的字典结构仅能存储单用户工时,需改为支持多用户的自定义类:
public class DailyWorkHours : INotifyPropertyChanged { private DateTime _date; public DateTime Date { get => _date; set { _date = value; OnPropertyChanged(); } } // 存储每个用户的工时,Key为用户标识,Value为工时数 public Dictionary<string, double> UserHours { get; set; } = new Dictionary<string, double>(); public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
ViewModel中对应的数据源更新为:
public ObservableCollection<DailyWorkHours> OreDate { get; set; } = new ObservableCollection<DailyWorkHours>();
2. ViewModel中管理动态列
在ViewModel中添加属性和方法,实现选中项变化时自动生成列:
// 所有用户列表 public ObservableCollection<string> ListaUtenti { get; set; } = new ObservableCollection<string>(); // 选中的用户(包含"全部用户"选项) private string _selectedUser; public string SelectedUser { get => _selectedUser; set { _selectedUser = value; OnPropertyChanged(); GenerateWorkHoursColumns(); } } // DataGrid的动态列集合 public ObservableCollection<DataGridColumn> WorkHoursColumns { get; set; } = new ObservableCollection<DataGridColumn>(); // 生成工时列的核心方法 private void GenerateWorkHoursColumns() { WorkHoursColumns.Clear(); // 添加固定的日期列 var dateColumn = new DataGridTextColumn { Width = new DataGridLength(1, DataGridLengthUnitType.Star), MinWidth = 100, Binding = new Binding("Date") { ConverterCulture = new CultureInfo("it-IT"), StringFormat = "dddd dd/MM" }, Header = "Date", IsReadOnly = true }; WorkHoursColumns.Add(dateColumn); // 根据选中项生成对应工时列 if (SelectedUser == "全部用户") { foreach (var user in ListaUtenti.Where(u => u != "全部用户")) { var hourColumn = new DataGridTextColumn { Width = new DataGridLength(1, DataGridLengthUnitType.Star), MinWidth = 100, Binding = new Binding($"UserHours[{user}]"), Header = user, IsReadOnly = true }; WorkHoursColumns.Add(hourColumn); } } else { var hourColumn = new DataGridTextColumn { Width = new DataGridLength(1, DataGridLengthUnitType.Star), MinWidth = 100, Binding = new Binding($"UserHours[{SelectedUser}]"), Header = "Working Hours", IsReadOnly = true }; WorkHoursColumns.Add(hourColumn); } }
3. 修改XAML绑定
更新DataGrid的XAML,绑定动态列集合并保留原有行样式:
<DataGrid Name="DgEsportazione" AutoGenerateColumns="False" IsReadOnly="True" ItemsSource="{Binding OreDate, UpdateSourceTrigger=PropertyChanged}" Columns="{Binding WorkHoursColumns}" Style="{StaticResource DataGridStyle1}"> <DataGrid.ItemContainerStyle> <Style TargetType="DataGridRow"> <Style.Triggers> <DataTrigger Binding="{Binding Date.DayOfWeek}" Value="Saturday"> <Setter Property="Background" Value="{StaticResource Background}" /> </DataTrigger> <DataTrigger Binding="{Binding Date.DayOfWeek}" Value="Sunday"> <Setter Property="Background" Value="{StaticResource Background}" /> </DataTrigger> </Style.Triggers> </Style> </DataGrid.ItemContainerStyle> </DataGrid>
4. 初始化ComboBox
在ViewModel构造函数中添加「全部用户」选项并设置默认选中:
public YourViewModel() { ListaUtenti.Insert(0, "全部用户"); SelectedUser = "全部用户"; }
关键说明
- 利用
ObservableCollection<DataGridColumn>实现列的动态增删,选中项变化时自动刷新列集合 - 通过字典索引器
UserHours[{user}]实现列与用户工时的绑定 - 保留了原有的周末行背景样式,仅调整绑定路径适配新数据模型
内容的提问来源于stack exchange,提问作者TutinaRosa
相关产品推荐
相关产品推荐

