WPF多级数据网格实现:如何从后台代码绑定子数据网格?
嘿,我来帮你搞定WPF里的多级嵌套DataGrid(带展开/折叠),还有后台代码绑定子网格的完整方案~
实现WPF多级嵌套DataGrid(带展开/折叠)
1. 先完善你的XAML结构
你之前写的主DataGrid列已经有了,现在要把RowDetailsTemplate里的子DataGrid绑定到正确的子集合,还可以加个展开/折叠按钮让交互更直观:
<DataGrid x:Name="MainJobsDataGrid" AutoGenerateColumns="False" RowDetailsVisibilityMode="Collapsed"> <!-- 默认折叠子网格 --> <DataGrid.Columns> <!-- 自定义展开/折叠按钮列 --> <DataGridTemplateColumn> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Button x:Name="ExpandCollapseBtn" Content="+" Click="ExpandCollapseBtn_Click"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTextColumn Header="Job Name" Binding="{Binding JobName}" /> <DataGridTextColumn Header="Job Number" Binding="{Binding JobNumber}" /> </DataGrid.Columns> <DataGrid.RowDetailsTemplate> <DataTemplate> <!-- 子DataGrid要绑定到当前Job对象的Employees集合,别直接写{Binding}哦 --> <DataGrid x:Name="EmployeesDataGrid" ItemsSource="{Binding Employees}" AutoGenerateColumns="False" Margin="20,0,0,0"> <!-- 缩进一下,层级更清晰 --> <DataGrid.Columns> <DataGridTextColumn Header="Employee Name" Binding="{Binding Name}" /> <DataGridTextColumn Header="Position" Binding="{Binding Position}" /> <DataGridTextColumn Header="Employee ID" Binding="{Binding EmployeeId}" /> </DataGrid.Columns> </DataGrid> </DataTemplate> </DataGrid.RowDetailsTemplate> </DataGrid>
2. 先定义好数据模型
后台需要先建两个类:一个是主数据(Job),一个是子数据(Employee),用ObservableCollection的话,数据变化时UI会自动更新,很方便:
// 子数据模型:员工信息 public class Employee { public string Name { get; set; } public string Position { get; set; } public int EmployeeId { get; set; } } // 主数据模型:工作信息,包含下属的员工集合 public class Job { public string JobName { get; set; } public string JobNumber { get; set; } // 这里就是子DataGrid要绑定的集合 public ObservableCollection<Employee> Employees { get; set; } = new ObservableCollection<Employee>(); }
3. 后台代码绑定数据源
在窗口的加载事件或者构造函数里,构造好数据,直接绑定给主DataGrid就行:
public MainWindow() { InitializeComponent(); Loaded += MainWindow_Loaded; } private void MainWindow_Loaded(object sender, RoutedEventArgs e) { // 先造点模拟数据,实际项目里你可以从数据库/接口拿 var jobList = new ObservableCollection<Job> { new Job { JobName = "电商平台开发", JobNumber = "JOB-2024-001", Employees = { new Employee { Name = "张三", Position = "后端开发", EmployeeId = 1001 }, new Employee { Name = "李四", Position = "前端开发", EmployeeId = 1002 } } }, new Job { JobName = "APP测试", JobNumber = "JOB-2024-002", Employees = { new Employee { Name = "王五", Position = "功能测试", EmployeeId = 2001 }, new Employee { Name = "赵六", Position = "性能测试", EmployeeId = 2002 } } } }; // 把数据绑定给主DataGrid MainJobsDataGrid.ItemsSource = jobList; }
4. 给展开/折叠按钮加逻辑
如果用了自定义的按钮,后台写个点击事件,切换行详情的可见性就行:
private void ExpandCollapseBtn_Click(object sender, RoutedEventArgs e) { var btn = sender as Button; var currentJob = btn.DataContext as Job; var targetRow = MainJobsDataGrid.ItemContainerGenerator.ContainerFromItem(currentJob) as DataGridRow; if (targetRow != null) { // 切换可见性 targetRow.DetailsVisibility = targetRow.DetailsVisibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible; // 按钮文本跟着变 btn.Content = targetRow.DetailsVisibility == Visibility.Visible ? "-" : "+"; } }
几个小提醒
- 子DataGrid的
ItemsSource一定要绑定到主数据对象的子集合(比如示例里的{Binding Employees}),之前你写的{Binding}会绑定到Job对象本身,肯定出不来数据哦。 - 如果需要动态增删数据,一定要用
ObservableCollection,普通List的话UI不会自动更新。 - 要是不想用自定义按钮,也可以把主DataGrid的
RowDetailsVisibilityMode设为VisibleWhenSelected,选中行就自动展开子网格。
内容的提问来源于stack exchange,提问作者Cricket Infatuation
相关产品推荐
相关产品推荐

