[英]Tricky issue with nested loop printing using C# and PrintDocument for WinForms application
I am working on a function in my C# WinForms application that lets me print warehouse pick orders to a PrintDocument, like so:我正在我的 C# WinForms 应用程序中处理 function,它允许我将仓库拣货单打印到 PrintDocument,如下所示:
I am using the following c# code to generate this:我正在使用以下 c# 代码来生成它:
private void pdPick_PrintPage(object sender, PrintPageEventArgs ev) {
pdPick.DefaultPageSettings.Landscape = true;
pdPick.DefaultPageSettings.Margins = new Margins ( 50, 50, 50, 50 );
pdPick.PrinterSettings.DefaultPageSettings.Margins = new Margins ( 50, 50, 50, 50 );
float yPos;
count = 0;
int leftMargin = (int)ev.MarginBounds.Left;
int rightMargin = (int)ev.MarginBounds.Right;
int topMargin = (int)ev.MarginBounds.Top;
int bottomMargin = (int)ev.MarginBounds.Bottom;
float linesPerPage;
bool moreRecs = true;
int lPos;
// If this is the first page, print a report header
if (pageCounter == 1) {
/* PRINT A REPORT HEADER HERE */
}
else { // if this is a subsequent page, print an abbreviated header
/* PRINT A PAGE HEADER HERE */
}
linesPerPage = ( ev.MarginBounds.Height - yPos ) / ( printFont.GetHeight ( ev.Graphics ) + 3 );
// Cycle through items
while ( curCount < boxCount && count < linesPerPage ) {
// PRINT ITEM DETAIL INFO FIRST...
// Now we cycle through the pick bins for the item...
foreach (PickItem record in pickItems) {
/*
*
* The issue is that I need to check inside this loop to see if I hit the bottom of the page,
* and if so, I need to start a new page and continue printing whatever remains inside this loop.
*
*
*/
}
yPos += 10;
count++;
curCount++;
moreRecs = count < boxItems.Count;
if ( moreRecs ) {
pageCounter++;
ev.HasMorePages = true;
}
else {
pageCounter = 1;
curCount = 0;
yPos += headerFont.Height + 10;
ev.HasMorePages = false;
return;
}
}
}
EDIT I stripped out the printing details to clarify the issue and address comments about refactoring.编辑我删除了打印细节以澄清问题并解决有关重构的评论。
The problem is this: As you can see from the code, there are two loops to the print sequence.问题是这样的:从代码中可以看出,打印序列有两个循环。 The first loop obtains a list of products in the pick order, from which I print the title, UPC code, and total units to pick for that item.第一个循环获取拣选订单中的产品列表,我从中打印标题、UPC 代码和要为该项目拣选的总单位数。 Inside that loop is another loop where I fetch the list of locations to pick the item from, so there could be multiple locations from which product needs to be retrieved to complete that line item.在该循环内是另一个循环,我在其中获取位置列表以从中选择项目,因此可能有多个位置需要从中检索产品以完成该订单项。 Now, everything works great as long as I don't go beyond one page.现在,只要我 go 不超出一页,一切都很好。 The challenge is this.挑战在于此。 Obviously I need to do a page break if I have more products that will fit within one page.显然,如果我有更多适合一页的产品,我需要分页。 The problem is, I need to check where I am in the page inside the second loop too, and if so, I need to start a new page and pick up where I left off.问题是,我也需要检查我在第二个循环内的页面中的位置,如果是这样,我需要开始一个新页面并从我离开的地方开始。 For example, with the third product in the list as shown in the included screenshot, if I print the first bin location and then run out of page room, I need to eject the page, print a new page header, then resume printing the rest of the bin locations for that product, then continue with any remaining products in the order.例如,对于列表中的第三个产品,如所附屏幕截图所示,如果我打印第一个 bin 位置然后用完页面空间,我需要弹出页面,打印新页面 header,然后继续打印 rest该产品的库位置,然后继续处理订单中的任何剩余产品。
From everything I can find, I can't simply do a ev.HasMorePages=true;
从我能找到的一切来看,我不能简单地做一个ev.HasMorePages=true;
inside that inner loop, because that would cause the entire print sequence to begin again, and that isn't what I want - it would just result in an infinite loop.在内循环中,因为这会导致整个打印序列重新开始,而这不是我想要的——它只会导致无限循环。 I have not been able to find any examples or SO posts on printing to a PrintDocument with nested loops.我无法找到任何关于使用嵌套循环打印到 PrintDocument 的示例或 SO 帖子。
Can anyone help me understand how to resolve this?谁能帮助我了解如何解决这个问题?
It won't be a tricky issue if you have the PickItem
objects of each group queued for printing.如果您让每个组的PickItem
对象排队等待打印,这将不是一个棘手的问题。 In this case, all what you need to do:在这种情况下,您需要做的就是:
Queue<PickItem>
.打印当前组并将其项目排入Queue<PickItem>
类型的 class 字段中。Y
position remains within the MarginBounds
.循环队列以打印每个项目并将其从集合中出列,同时Y
position 保留在MarginBounds
内。Y
position plus the fixed/variable line height (your lines/rows calculations for the groups and items) exceeds the e.MarginBounds.Bottom
value.在绘制组和项目时,如果Y
position 加上固定/可变行高(您对组和项目的行/行计算)超过e.MarginBounds.Bottom
值,则请求新页面。Example例子
public partial class SomeForm : Form
{
private readonly Queue<PickItem> pickItemsQueue;
private int pageNumber;
private int curGroup;
public SomeForm()
{
InitializeComponent();
pickItemsQueue = new Queue<PickItem>();
pdPick.DefaultPageSettings.Landscape = true;
pdPick.DefaultPageSettings.Margins = new Margins(50, 50, 50, 50);
pdPick.PrinterSettings.DefaultPageSettings.Margins = new Margins(50, 50, 50, 50);
}
private void PrintCaller()
{
pageNumber = 0;
curGroup = 0;
pickItemsQueue.Clear();
using (var d = new PrintPreviewDialog())
{
d.Document = pdPick;
d.ShowDialog(this);
}
}
private void pdPick_PrintPage(object sender, PrintPageEventArgs e)
{
var lineHeight = (int)Font.GetHeight(e.Graphics) + 10;
int ypos = e.MarginBounds.Y;
pageNumber++;
// If this is the first page, print a report header
if (pageNumber == 1) {
/* PRINT A REPORT HEADER HERE */
}
else {
// if this is a subsequent page, print an abbreviated header
}
while (curGroup < groups.Count)
{
if (ypos + lineHeight > e.MarginBounds.Bottom)
{
e.HasMorePages = true;
return;
}
if (!pickItemsQueue.Any())
{
// PRINT ITEM DETAIL INFO FIRST...
// Adjust the ypos as you like...
ypos += lineHeight;
// Create a new queue or add the pickItems to the current instance...
pickItemsQueue = new Queue<PickItem>(pickItems);
}
while (pickItemsQueue.Count > 0)
{
if (ypos + lineHeight > e.MarginBounds.Bottom)
{
e.HasMorePages = true;
return;
}
var item = pickItemsQueue.Dequeue();
// Print it and update the ypos...
ypos += lineHeight;
}
curGroup++;
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.