如何实现GridView中选中行的单页打印?
解决方案:将选中的GridView行合并为单份报表打印
我明白你的问题了——现在你的代码会把每一行选中的记录单独生成一份报表打印,而你想要把所有选中的行合并到同一份报表里一次性打印。咱们来一步步解决这个问题:
问题根源分析
你原来的代码在循环中每次找到选中行就执行一次查询,而且会覆盖之前的数据源(tblRpt1),最后要么只打印最后一条选中记录,要么如果把打印逻辑放在循环里,就会每条记录单独打印。核心问题是没有把所有选中行的数据合并成一个统一的数据源。
分步解决方案
1. 收集所有选中行的ID
首先遍历GridView,把选中行的关键ID(比如你的Pro_ID)收集到一个列表中:
List<int> selectedProIds = new List<int>(); for (int i = 0; i < DgvSale.Rows.Count; i++) { // 第8列是你的复选框列,确认索引是否正确 if (Convert.ToBoolean(DgvSale.Rows[i].Cells[8].Value)) { // 假设Cells[0]是Pro_ID列,根据你的GridView实际列调整索引 int proId = Convert.ToInt32(DgvSale.Rows[i].Cells[0].Value); selectedProIds.Add(proId); } } // 处理未选中任何行的情况 if (selectedProIds.Count == 0) { MessageBox.Show("请选择要打印的行!"); return; }
2. 一次性查询所有选中行的数据(参数化查询,避免SQL注入)
不要每次查询单条记录,而是用IN子句一次性获取所有选中行的数据,同时使用参数化查询防止SQL注入风险(这比直接拼接字符串安全得多):
// 构造参数占位符,比如@id0, @id1... string paramPlaceholders = string.Join(", ", selectedProIds.Select((_, index) => $"@id{index}")); // 使用JOIN语法替代逗号连接表,更清晰且避免笛卡尔积 string sql = @"SELECT [Order_ID] as 'رقم الفاتورة',talb_ID as 'طلب',[Cust_Name] as 'اسم العميل', Products.Pro_Name as 'المنتج',Products.Group_ID as 'قسم',Products_Group.Group_Name as 'اسم القسم', [Sales_Detalis].[Qty] as 'الكمية',[Price] as 'السعر',[User_Name] as 'الكاشير',[Date] as 'التاريخ', [Unit] as 'الوحدة',[Sales_Detalis].Tax_Value as 'الضريبة',Price_Tax as 'السعر بعد الضريبة', [typetalab] as 'نوع الطلب',[priceservic] as 'خدمة',[shiftname] as 'شيفت',notes as 'ملاحظات', shiftnum as 'شيفت رقم',Print_Group.Print_Name,Print_Group.Name_Group FROM [dbo].[Sales_Detalis] JOIN Products ON Products.Pro_ID = Sales_Detalis.Pro_ID JOIN Products_Group ON Products.Group_ID = Products_Group.Group_ID JOIN Print_Group ON Print_Group.Name_Group = Products.Group_ID WHERE Products.Pro_ID IN ({0}) AND Order_ID = @orderId ORDER BY Order_ID ASC"; // 替换占位符生成最终SQL sql = string.Format(sql, paramPlaceholders); // 创建参数化命令 SqlCommand cmd = new SqlCommand(sql); cmd.Parameters.AddWithValue("@orderId", id); // 添加每个选中Pro_ID的参数 for (int i = 0; i < selectedProIds.Count; i++) { cmd.Parameters.AddWithValue($"@id{i}", selectedProIds[i]); } // 执行查询获取合并后的数据源(根据你的db.readData方法调整,确保支持参数化命令) DataTable tblRpt1 = db.readData(cmd);
3. 绑定合并后的数据源到报表并打印
现在tblRpt1包含了所有选中行的数据,直接绑定到报表即可一次性打印所有内容:
if (Properties.Settings.Default.SalePrintKind == "8CM") { devOrderSales2 rpt = new devOrderSales2(); rpt.DataSource = tblRpt1; rpt.DataMember = "OrderSales2"; rpt.Parameters["ID1"].Value = id; rpt.PrinterName = Properties.Settings.Default.PrinterNameSteker; rpt.xrTableCell8.Visible = true; if (Properties.Settings.Default.saleprintauto == "0") { rpt.Print(); } else if (Properties.Settings.Default.saleprintauto == "1") { rpt.ShowPreviewDialog(); } }
额外注意事项
- 报表布局检查:确保你的
devOrderSales2报表的Detail带区已经正确绑定数据源字段,这样每条选中的记录会自动在报表中生成一行,所有内容会在同一份报表中显示(如果数据过多会自动分页,但仍是同一份报表)。 - 参数化查询适配:如果你的
db.readData方法不支持直接传入SqlCommand,可以修改该方法支持参数化查询,或者使用其他方式构造安全的查询语句,绝对不要直接拼接ID到SQL字符串中(会导致SQL注入漏洞)。 - 列索引确认:确认GridView中复选框列(Cells[8])和Pro_ID列(Cells[0])的索引与你的实际界面一致,避免索引错误导致的逻辑问题。
内容的提问来源于stack exchange,提问作者mazentq
相关产品推荐
相关产品推荐

