【问题标题】:Tricky issue with nested loop printing using C# and PrintDocument for WinForms application使用 C# 和 PrintDocument for WinForms 应用程序进行嵌套循环打印的棘手问题
【发布时间】:2022-12-09 11:14:21
【问题描述】:

我正在我的 C# WinForms 应用程序中开发一个函数,它允许我将仓库拣货单打印到 PrintDocument,如下所示:

我正在使用以下 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;
                }
            } 
        }

编辑我删除了打印细节以澄清问题并解决有关重构的问题。

问题是这样的:从代码中可以看出,打印序列有两个循环。第一个循环获取拣选订单中的产品列表,我从中打印标题、UPC 代码和要为该项目拣选的总单位数。里面那个循环是其他循环我获取位置列表以从中选择项目,因此可能有多个位置需要从中检索产品以完成该订单项。 现在,只要我不超出一页,一切都很好。 挑战在于此。显然,如果我有更多适合一页的产品,我需要分页。问题是,我也需要检查我在第二个循环内的页面中的位置,如果是这样,我需要开始一个新页面并从我离开的地方开始。例如,对于列表中的第三个产品(如随附的屏幕截图所示),如果我打印第一个 bin 位置然后用完页面空间,我需要弹出页面,打印一个新的页眉,然后继续打印其余部分该产品的库位,然后继续处理订单中的任何剩余产品。

从我能找到的所有内容来看,我不能简单地在该内部循环中执行 ev.HasMorePages=true;,因为这会导致整个打印序列重新开始,而这不是我想要的 - 它只会导致无限循环.我无法找到任何关于使用嵌套循环打印到 PrintDocument 的示例或 SO 帖子。

谁能帮助我了解如何解决这个问题?

【问题讨论】:

  • 看起来这段代码应该进行认真的重构。我强烈建议重构,然后在更新的代码中进行编辑,以便我们可以更快地理解它。否则请忽略我:p
  • 你需要准备完整的报告(我的意思是一些东西的列表),就好像根本没有分页一样。然后在第二步将它分成几页。
  • 在 C# 中打印并没有真正为您提供该选项。打印生命周期中的所有内容都发生在文档的 PrintPage 事件中。从逻辑上讲,您可以设置 HasMorePages=true 以转到文档的下一页,这只会再次调用 PrintPage 事件,在这种情况下,这将创建一个无限循环,因为它将重新加载当前产品的库位置列表.如果我在打印 bin 位置列表时页面空间不足,我需要能够跳出页面并从内部循环开始一个新页面。
  • 我同意第一条评论。大量重构。目标应该是关注点分离。将打印“一个东西”或“另一个东西”(如“标题”或“缩写标题”,“产品项目”等)的所有“讨厌”技术细节封装在一个类中负责页面管理(页码、分页符等)。印刷人员不应该关心(a)必须印刷多少不同的“东西”,也不应该关心这些“东西”来自哪里。对于使用上述打印类的另一种方法或类,这是一个不同的问题......
  • 我很欣赏关于重构的 cmets,是的,我可以创建函数来包含打印细节,但它仍然没有解决我所要求的基本问题。最外层的循环按顺序循环浏览产品,很容易处理转到下一页。诀窍是如何为内部循环做同样的事情。简单地调用 ev.HasMorePages 是行不通的,因为它只会产生无限循环问题。

标签: c# winforms printdocument


【解决方案1】:

如果你有每个组的 PickItem 对象,这将不是一个棘手的问题排队用于打印。在这种情况下,您需要做的就是:

  1. 打印当前组和排队它在Queue&lt;PickItem&gt; 类型的类字段中的项。
  2. 循环队列以打印每个项目并出队它从集合中取出,而 Y 位置仍在 MarginBounds 中。
  3. 绘制组和项目时,如果Y位置加上固定/可变行高(组和项目的行/行计算)超过e.MarginBounds.Bottom值,则请求新页面。

    例子

    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++;
            }
        }
    }
    

【讨论】:

    猜你喜欢
    • 2012-09-14
    • 2019-02-27
    • 1970-01-01
    • 1970-01-01
    • 2022-11-21
    • 1970-01-01
    • 1970-01-01
    • 2012-01-13
    • 1970-01-01
    相关资源
    最近更新 更多