You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 01:47:46