I am working on a function in my C# WinForms application that lets me print warehouse pick orders to a PrintDocument, like so:
I am using the following c# code to generate this:
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. 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. 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.
From everything I can find, I can't simply do a 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.
Can anyone help me understand how to resolve this?
CodePudding user response:
It won't be a tricky issue if you have the PickItem
objects of each group queued for printing. In this case, all what you need to do:
- Print the current group and enqueue its items in a class field of type
Queue<PickItem>
. - Loop the queue to print each item and dequeue it from the collection while the
Y
position remains within theMarginBounds
. - While drawing the groups and items, request a new page if the
Y
position plus the fixed/variable line height (your lines/rows calculations for the groups and items) exceeds thee.MarginBounds.Bottom
value.
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 ;
}
}
}