WPF+MVVM实现DataGrid相同内容单元格合并方法
嘿,针对你的职业培训规划项目需求——在MVVM模式下实现DataGrid相同内容单元格合并(比如学员连续几周修读同一课程时合并课程单元格),同时支持DIN A3/A2规格打印,我给你整理了一套落地性强的方案:
实现MVVM模式下DataGrid单元格合并+打印的完整方案
1. 先搞定ViewModel层的合并逻辑(核心)
MVVM模式要求业务逻辑尽量放在ViewModel层,所以我们需要先处理原始的每周课程数据,生成带有合并判断属性的集合,避免在View层写业务代码:
1.1 定义基础模型与合并用模型
// 原始每周课程模型 public class WeeklyCourse : ObservableObject { public int WeekNumber { get; set; } public string CourseName { get; set; } // 其他业务属性:讲师、课时、教室等 } // 用于单元格合并的包装模型 public class CourseMergeItem : ObservableObject { public int WeekNumber { get; set; } public string CourseName { get; set; } public int RowSpan { get; set; } // 单元格需要跨多少行合并 public bool IsCourseVisible { get; set; } // 标记当前行是否显示课程名(仅合并组的第一行显示) }
1.2 在ViewModel中处理数据合并
public class TrainingPlanViewModel : ObservableObject { public ObservableCollection<CourseMergeItem> MergedCourseList { get; set; } public TrainingPlanViewModel() { // 假设从数据库/接口加载原始每周课程数据 var originalWeeklyCourses = LoadWeeklyTrainingData(); MergedCourseList = GenerateMergedCourseItems(originalWeeklyCourses); } private ObservableCollection<CourseMergeItem> GenerateMergedCourseItems(List<WeeklyCourse> originalData) { var mergedItems = new ObservableCollection<CourseMergeItem>(); if (originalData == null || !originalData.Any()) return mergedItems; // 遍历原始数据,分组连续相同的课程 var currentCourse = originalData[0]; int currentRowSpan = 1; for (int i = 1; i < originalData.Count; i++) { var nextCourse = originalData[i]; if (nextCourse.CourseName == currentCourse.CourseName) { currentRowSpan++; } else { // 添加合并组的第一行 mergedItems.Add(new CourseMergeItem { WeekNumber = currentCourse.WeekNumber, CourseName = currentCourse.CourseName, RowSpan = currentRowSpan, IsCourseVisible = true }); // 添加合并组的后续行(隐藏课程名,RowSpan为1) for (int j = 1; j < currentRowSpan; j++) { mergedItems.Add(new CourseMergeItem { WeekNumber = currentCourse.WeekNumber + j, CourseName = currentCourse.CourseName, RowSpan = 1, IsCourseVisible = false }); } // 重置当前课程和跨度 currentCourse = nextCourse; currentRowSpan = 1; } } // 添加最后一组数据 mergedItems.Add(new CourseMergeItem { WeekNumber = currentCourse.WeekNumber, CourseName = currentCourse.CourseName, RowSpan = currentRowSpan, IsCourseVisible = true }); for (int j = 1; j < currentRowSpan; j++) { mergedItems.Add(new CourseMergeItem { WeekNumber = currentCourse.WeekNumber + j, CourseName = currentCourse.CourseName, RowSpan = 1, IsCourseVisible = false }); } return mergedItems; } }
2. View层实现单元格合并渲染
在XAML中,通过绑定ViewModel的RowSpan和IsCourseVisible属性,结合DataGrid的样式实现单元格合并:
<Window.Resources> <BooleanToVisibilityConverter x:Key="BoolToVis" /> </Window.Resources> <DataGrid ItemsSource="{Binding MergedCourseList}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False" RowHeaderWidth="0"> <!-- 周次列 --> <DataGridTextColumn Header="周次" Binding="{Binding WeekNumber}" Width="*" /> <!-- 课程列(核心合并逻辑) --> <DataGridTemplateColumn Header="课程名称" Width="2*"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="{Binding CourseName}" Visibility="{Binding IsCourseVisible, Converter={StaticResource BoolToVis}}" VerticalAlignment="Center" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellStyle> <Style TargetType="DataGridCell"> <!-- 设置单元格跨行数 --> <Setter Property="Grid.RowSpan" Value="{Binding RowSpan}" /> <!-- 隐藏重复行的单元格边框,避免视觉割裂 --> <Style.Triggers> <DataTrigger Binding="{Binding IsCourseVisible}" Value="False"> <Setter Property="BorderThickness" Value="0" /> </DataTrigger> </Style.Triggers> </Style> </DataGridTemplateColumn.CellStyle> </DataGridTemplateColumn> <!-- 其他业务列:讲师、课时等 --> </DataGrid>
3. 适配DIN A3/A2规格的打印
你已经实现了DataGrid打印功能,只需要调整打印参数适配大尺寸纸张:
3.1 配置打印纸张尺寸
private void PrintTrainingPlan(DataGrid targetGrid) { var printDialog = new PrintDialog(); // 设置为DIN A3(毫米转百分之一英寸:297mm≈1169,420mm≈1654) var a3Size = new PageMediaSize(PageMediaSizeName.ISOC, 1169, 1654); // 如果需要A2,替换为:PageMediaSizeName.ISOB,尺寸594mm≈2339,420mm≈1654 printDialog.PrintTicket.PageMediaSize = a3Size; if (printDialog.ShowDialog() == true) { // 打印前强制更新布局,确保合并单元格渲染正确 targetGrid.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity)); targetGrid.Arrange(new Rect(0, 0, targetGrid.DesiredSize.Width, targetGrid.DesiredSize.Height)); // 执行打印 printDialog.PrintVisual(targetGrid, "职业培训规划表"); } }
3.2 打印优化建议
- 如果DataGrid内容过长,可以添加分页逻辑,或者设置打印缩放比例适配大纸张
- 测试不同打印机的大尺寸纸张支持情况,调整边距参数
内容的提问来源于stack exchange,提问作者Björn Steinbrink
相关产品推荐
相关产品推荐

